aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-03-07 16:16:02 +0000
committerPeter Maydell <peter.maydell@linaro.org>2019-03-07 16:16:02 +0000
commit6cb4f6db4f4367faa33da85b15f75bbbd2bed2a6 (patch)
tree97bcef90f31e66f70fc16fc4a6ec71b076a9d7c8
parent21afe115a49776aa07f4d93d22b9ad133fd183a5 (diff)
parent8f1c89ec7443e4fa2cf106d8fa1c1c97b6ddeffb (diff)
downloadqemu-6cb4f6db4f4367faa33da85b15f75bbbd2bed2a6.zip
qemu-6cb4f6db4f4367faa33da85b15f75bbbd2bed2a6.tar.gz
qemu-6cb4f6db4f4367faa33da85b15f75bbbd2bed2a6.tar.bz2
Merge remote-tracking branch 'remotes/cleber/tags/python-next-pull-request' into staging
Python queue, 2019-02-22 Python: * introduce "python" directory with module namespace * log QEMU launch command line on qemu.QEMUMachine Acceptance Tests: * initrd 4GiB+ test * migration test * multi vm support in test class * bump Avocado version and drop ":avocado: enable" # gpg: Signature made Fri 22 Feb 2019 19:37:07 GMT # gpg: using RSA key 657E8D33A5F209F3 # gpg: Good signature from "Cleber Rosa <crosa@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 7ABB 96EB 8B46 B94D 5E0F E9BB 657E 8D33 A5F2 09F3 * remotes/cleber/tags/python-next-pull-request: Acceptance tests: expect boot to extract 2GiB+ initrd with linux-v4.16 Acceptance tests: use linux-3.6 and set vm memory to 4GiB tests.acceptance: adds simple migration test tests.acceptance: adds multi vm capability for acceptance tests scripts/qemu.py: log QEMU launch command line Introduce a Python module structure Acceptance tests: drop usage of ":avocado: enable" Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rwxr-xr-xconfigure1
-rw-r--r--docs/devel/testing.rst42
-rw-r--r--python/qemu/__init__.py (renamed from scripts/qemu.py)12
-rw-r--r--python/qemu/qmp.py (renamed from scripts/qmp/qmp.py)0
-rw-r--r--python/qemu/qtest.py (renamed from scripts/qtest.py)5
-rwxr-xr-xscripts/device-crash-test2
-rw-r--r--scripts/qmp/__init__.py0
-rwxr-xr-xscripts/qmp/qemu-ga-client5
-rwxr-xr-xscripts/qmp/qmp-shell4
-rwxr-xr-xscripts/render_block_graph.py2
-rw-r--r--tests/acceptance/avocado_qemu/__init__.py30
-rw-r--r--tests/acceptance/boot_linux_console.py1
-rw-r--r--tests/acceptance/linux_initrd.py52
-rw-r--r--tests/acceptance/migration.py53
-rw-r--r--tests/acceptance/version.py1
-rw-r--r--tests/acceptance/virtio_version.py3
-rw-r--r--tests/acceptance/vnc.py1
-rw-r--r--tests/migration/guestperf/engine.py7
-rwxr-xr-xtests/qemu-iotests/2352
-rwxr-xr-xtests/qemu-iotests/2382
-rw-r--r--tests/qemu-iotests/iotests.py4
-rw-r--r--tests/requirements.txt2
-rwxr-xr-xtests/vm/basevm.py2
23 files changed, 193 insertions, 40 deletions
diff --git a/configure b/configure
index 47bf617..5921d08 100755
--- a/configure
+++ b/configure
@@ -7674,6 +7674,7 @@ LINKS="$LINKS pc-bios/qemu-icon.bmp"
LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit
LINKS="$LINKS tests/acceptance tests/data"
LINKS="$LINKS tests/qemu-iotests/check"
+LINKS="$LINKS python"
for bios_file in \
$source_path/pc-bios/*.bin \
$source_path/pc-bios/*.lid \
diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst
index 135743a..60f897d 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing.rst
@@ -600,7 +600,6 @@ the ``avocado_qemu.Test`` class. Here's a simple usage example:
class Version(Test):
"""
- :avocado: enable
:avocado: tags=quick
"""
def test_qmp_human_info_version(self):
@@ -634,7 +633,46 @@ instance, available at ``self.vm``. Because many tests will tweak the
QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``)
is left to the test writer.
-At test "tear down", ``avocado_qemu.Test`` handles the QEMUMachine
+The base test class has also support for tests with more than one
+QEMUMachine. The way to get machines is through the ``self.get_vm()``
+method which will return a QEMUMachine instance. The ``self.get_vm()``
+method accepts arguments that will be passed to the QEMUMachine creation
+and also an optional `name` attribute so you can identify a specific
+machine and get it more than once through the tests methods. A simple
+and hypothetical example follows:
+
+.. code::
+
+ from avocado_qemu import Test
+
+
+ class MultipleMachines(Test):
+ """
+ :avocado: enable
+ """
+ def test_multiple_machines(self):
+ first_machine = self.get_vm()
+ second_machine = self.get_vm()
+ self.get_vm(name='third_machine').launch()
+
+ first_machine.launch()
+ second_machine.launch()
+
+ first_res = first_machine.command(
+ 'human-monitor-command',
+ command_line='info version')
+
+ second_res = second_machine.command(
+ 'human-monitor-command',
+ command_line='info version')
+
+ third_res = self.get_vm(name='third_machine').command(
+ 'human-monitor-command',
+ command_line='info version')
+
+ self.assertEquals(first_res, second_res, third_res)
+
+At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
shutdown.
QEMUMachine
diff --git a/scripts/qemu.py b/python/qemu/__init__.py
index f7269ee..fd144c0 100644
--- a/scripts/qemu.py
+++ b/python/qemu/__init__.py
@@ -16,12 +16,13 @@ import errno
import logging
import os
import subprocess
-import qmp.qmp
import re
import shutil
import socket
import tempfile
+from . import qmp
+
LOG = logging.getLogger(__name__)
@@ -66,7 +67,7 @@ class QEMUMachineAddDeviceError(QEMUMachineError):
failures reported by the QEMU binary itself.
"""
-class MonitorResponseError(qmp.qmp.QMPError):
+class MonitorResponseError(qmp.QMPError):
"""
Represents erroneous QMP monitor reply
"""
@@ -266,8 +267,8 @@ class QEMUMachine(object):
self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
self._qemu_log_file = open(self._qemu_log_path, 'wb')
- self._qmp = qmp.qmp.QEMUMonitorProtocol(self._vm_monitor,
- server=True)
+ self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor,
+ server=True)
def _post_launch(self):
self._qmp.accept()
@@ -319,6 +320,7 @@ class QEMUMachine(object):
self._pre_launch()
self._qemu_full_args = (self._wrapper + [self._binary] +
self._base_args() + self._args)
+ LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
self._popen = subprocess.Popen(self._qemu_full_args,
stdin=devnull,
stdout=self._qemu_log_file,
@@ -383,7 +385,7 @@ class QEMUMachine(object):
"""
reply = self.qmp(cmd, conv_keys, **args)
if reply is None:
- raise qmp.qmp.QMPError("Monitor is closed")
+ raise qmp.QMPError("Monitor is closed")
if "error" in reply:
raise MonitorResponseError(reply)
return reply["return"]
diff --git a/scripts/qmp/qmp.py b/python/qemu/qmp.py
index 5c8cf6a..5c8cf6a 100644
--- a/scripts/qmp/qmp.py
+++ b/python/qemu/qmp.py
diff --git a/scripts/qtest.py b/python/qemu/qtest.py
index afac3fe..eb45824 100644
--- a/scripts/qtest.py
+++ b/python/qemu/qtest.py
@@ -13,7 +13,8 @@
import socket
import os
-import qemu
+
+from . import QEMUMachine
class QEMUQtestProtocol(object):
@@ -79,7 +80,7 @@ class QEMUQtestProtocol(object):
self._sock.settimeout(timeout)
-class QEMUQtestMachine(qemu.QEMUMachine):
+class QEMUQtestMachine(QEMUMachine):
'''A QEMU VM'''
def __init__(self, binary, args=None, name=None, test_dir="/var/tmp",
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index 2a13fa4..a674891 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -25,6 +25,7 @@ check for crashes and unexpected errors.
"""
from __future__ import print_function
+import os
import sys
import glob
import logging
@@ -34,6 +35,7 @@ import random
import argparse
from itertools import chain
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
from qemu import QEMUMachine
logger = logging.getLogger('device-crash-test')
diff --git a/scripts/qmp/__init__.py b/scripts/qmp/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/scripts/qmp/__init__.py
+++ /dev/null
diff --git a/scripts/qmp/qemu-ga-client b/scripts/qmp/qemu-ga-client
index e8cb764..30cf8a9 100755
--- a/scripts/qmp/qemu-ga-client
+++ b/scripts/qmp/qemu-ga-client
@@ -37,10 +37,13 @@
#
from __future__ import print_function
+import os
+import sys
import base64
import random
-import qmp
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu import qmp
class QemuGuestAgent(qmp.QEMUMonitorProtocol):
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index 7701407..9fec46e 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -66,7 +66,6 @@
# sent to QEMU, which is useful for debugging and documentation generation.
from __future__ import print_function
-import qmp
import json
import ast
import readline
@@ -76,6 +75,9 @@ import errno
import atexit
import shlex
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu import qmp
+
class QMPCompleter(list):
def complete(self, text, state):
for cmd in self:
diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
index ed7e581..3e9d282 100755
--- a/scripts/render_block_graph.py
+++ b/scripts/render_block_graph.py
@@ -23,6 +23,8 @@ import sys
import subprocess
import json
from graphviz import Digraph
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
from qemu import MonitorResponseError
diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py
index 1e54fd5..a66ec72 100644
--- a/tests/acceptance/avocado_qemu/__init__.py
+++ b/tests/acceptance/avocado_qemu/__init__.py
@@ -10,12 +10,12 @@
import os
import sys
+import uuid
import avocado
-SRC_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
-SRC_ROOT_DIR = os.path.abspath(os.path.dirname(SRC_ROOT_DIR))
-sys.path.append(os.path.join(SRC_ROOT_DIR, 'scripts'))
+SRC_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..')
+sys.path.append(os.path.join(SRC_ROOT_DIR, 'python'))
from qemu import QEMUMachine
@@ -42,13 +42,29 @@ def pick_default_qemu_bin():
class Test(avocado.Test):
def setUp(self):
- self.vm = None
+ self._vms = {}
self.qemu_bin = self.params.get('qemu_bin',
default=pick_default_qemu_bin())
if self.qemu_bin is None:
self.cancel("No QEMU binary defined or found in the source tree")
- self.vm = QEMUMachine(self.qemu_bin)
+
+ def _new_vm(self, *args):
+ vm = QEMUMachine(self.qemu_bin)
+ if args:
+ vm.add_args(*args)
+ return vm
+
+ @property
+ def vm(self):
+ return self.get_vm(name='default')
+
+ def get_vm(self, *args, name=None):
+ if not name:
+ name = str(uuid.uuid4())
+ if self._vms.get(name) is None:
+ self._vms[name] = self._new_vm(*args)
+ return self._vms[name]
def tearDown(self):
- if self.vm is not None:
- self.vm.shutdown()
+ for vm in self._vms.values():
+ vm.shutdown()
diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py
index 98324f7..beeb1e5 100644
--- a/tests/acceptance/boot_linux_console.py
+++ b/tests/acceptance/boot_linux_console.py
@@ -18,7 +18,6 @@ class BootLinuxConsole(Test):
Boots a x86_64 Linux kernel and checks that the console is operational
and the kernel command line is properly passed from QEMU to the kernel
- :avocado: enable
:avocado: tags=x86_64
"""
diff --git a/tests/acceptance/linux_initrd.py b/tests/acceptance/linux_initrd.py
index 737355c..fbdb48e 100644
--- a/tests/acceptance/linux_initrd.py
+++ b/tests/acceptance/linux_initrd.py
@@ -8,6 +8,7 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
+import logging
import tempfile
from avocado.utils.process import run
@@ -18,20 +19,21 @@ class LinuxInitrd(Test):
"""
Checks QEMU evaluates correctly the initrd file passed as -initrd option.
- :avocado: enable
:avocado: tags=x86_64
"""
- timeout = 60
+ timeout = 300
- def test_with_2gib_file_should_exit_error_msg(self):
+ def test_with_2gib_file_should_exit_error_msg_with_linux_v3_6(self):
"""
Pretends to boot QEMU with an initrd file with size of 2GiB
and expect it exits with error message.
+ Fedora-18 shipped with linux-3.6 which have not supported xloadflags
+ cannot support more than 2GiB initrd.
"""
- kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/'
- 'Everything/x86_64/os/images/pxeboot/vmlinuz')
- kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora/li'
+ 'nux/releases/18/Fedora/x86_64/os/images/pxeboot/vmlinuz')
+ kernel_hash = '41464f68efe42b9991250bed86c7081d2ccdbb21'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
max_size = 2 * (1024 ** 3) - 1
@@ -39,10 +41,44 @@ class LinuxInitrd(Test):
initrd.seek(max_size)
initrd.write(b'\0')
initrd.flush()
- cmd = "%s -kernel %s -initrd %s" % (self.qemu_bin, kernel_path,
- initrd.name)
+ cmd = "%s -kernel %s -initrd %s -m 4096" % (
+ self.qemu_bin, kernel_path, initrd.name)
res = run(cmd, ignore_status=True)
self.assertEqual(res.exit_status, 1)
expected_msg = r'.*initrd is too large.*max: \d+, need %s.*' % (
max_size + 1)
self.assertRegex(res.stderr_text, expected_msg)
+
+ def test_with_2gib_file_should_work_with_linux_v4_16(self):
+ """
+ QEMU has supported up to 4 GiB initrd for recent kernel
+ Expect guest can reach 'Unpacking initramfs...'
+ """
+ kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/'
+ 'Everything/x86_64/os/images/pxeboot/vmlinuz')
+ kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ max_size = 2 * (1024 ** 3) + 1
+
+ with tempfile.NamedTemporaryFile() as initrd:
+ initrd.seek(max_size)
+ initrd.write(b'\0')
+ initrd.flush()
+
+ self.vm.set_machine('pc')
+ self.vm.set_console()
+ kernel_command_line = 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line,
+ '-initrd', initrd.name,
+ '-m', '5120')
+ self.vm.launch()
+ console = self.vm.console_socket.makefile()
+ console_logger = logging.getLogger('console')
+ while True:
+ msg = console.readline()
+ console_logger.debug(msg.strip())
+ if 'Unpacking initramfs...' in msg:
+ break
+ if 'Kernel panic - not syncing' in msg:
+ self.fail("Kernel panic reached")
diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py
new file mode 100644
index 0000000..6115cf6
--- /dev/null
+++ b/tests/acceptance/migration.py
@@ -0,0 +1,53 @@
+# Migration test
+#
+# Copyright (c) 2019 Red Hat, Inc.
+#
+# Authors:
+# Cleber Rosa <crosa@redhat.com>
+# Caio Carrara <ccarrara@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+
+from avocado_qemu import Test
+
+from avocado.utils import network
+from avocado.utils import wait
+
+
+class Migration(Test):
+ """
+ :avocado: enable
+ """
+
+ timeout = 10
+
+ @staticmethod
+ def migration_finished(vm):
+ return vm.command('query-migrate')['status'] in ('completed', 'failed')
+
+ def _get_free_port(self):
+ port = network.find_free_port()
+ if port is None:
+ self.cancel('Failed to find a free port')
+ return port
+
+
+ def test_migration_with_tcp_localhost(self):
+ source_vm = self.get_vm()
+ dest_uri = 'tcp:localhost:%u' % self._get_free_port()
+ dest_vm = self.get_vm('-incoming', dest_uri)
+ dest_vm.launch()
+ source_vm.launch()
+ source_vm.qmp('migrate', uri=dest_uri)
+ wait.wait_for(
+ self.migration_finished,
+ timeout=self.timeout,
+ step=0.1,
+ args=(source_vm,)
+ )
+ self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed')
+ self.assertEqual(source_vm.command('query-migrate')['status'], 'completed')
+ self.assertEqual(dest_vm.command('query-status')['status'], 'running')
+ self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate')
diff --git a/tests/acceptance/version.py b/tests/acceptance/version.py
index 13b0a74..67c2192 100644
--- a/tests/acceptance/version.py
+++ b/tests/acceptance/version.py
@@ -14,7 +14,6 @@ from avocado_qemu import Test
class Version(Test):
"""
- :avocado: enable
:avocado: tags=quick
"""
def test_qmp_human_info_version(self):
diff --git a/tests/acceptance/virtio_version.py b/tests/acceptance/virtio_version.py
index ce99025..37fc01e 100644
--- a/tests/acceptance/virtio_version.py
+++ b/tests/acceptance/virtio_version.py
@@ -11,7 +11,7 @@ Check compatibility of virtio device types
import sys
import os
-sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import QEMUMachine
from avocado_qemu import Test
@@ -61,7 +61,6 @@ class VirtioVersionCheck(Test):
same device tree created by `disable-modern` and
`disable-legacy`.
- :avocado: enable
:avocado: tags=x86_64
"""
diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py
index b1ef9d7..064ceab 100644
--- a/tests/acceptance/vnc.py
+++ b/tests/acceptance/vnc.py
@@ -13,7 +13,6 @@ from avocado_qemu import Test
class Vnc(Test):
"""
- :avocado: enable
:avocado: tags=vnc,quick
"""
def test_no_vnc(self):
diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py
index 398e3f2..0e30466 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration/guestperf/engine.py
@@ -24,13 +24,14 @@ import re
import sys
import time
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'scripts'))
-import qemu
-import qmp.qmp
from guestperf.progress import Progress, ProgressStats
from guestperf.report import Report
from guestperf.timings import TimingRecord, Timings
+sys.path.append(os.path.join(os.path.dirname(__file__),
+ '..', '..', '..', 'python'))
+import qemu
+
class Engine(object):
diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235
index d6edd97..75c203b 100755
--- a/tests/qemu-iotests/235
+++ b/tests/qemu-iotests/235
@@ -23,7 +23,7 @@ import os
import iotests
from iotests import qemu_img_create, qemu_io, file_path, log
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import QEMUMachine
diff --git a/tests/qemu-iotests/238 b/tests/qemu-iotests/238
index f81ee11..688abc9 100755
--- a/tests/qemu-iotests/238
+++ b/tests/qemu-iotests/238
@@ -23,7 +23,7 @@ import os
import iotests
from iotests import log
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import QEMUMachine
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 4910fb2..3d15571 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -32,8 +32,8 @@ import atexit
import io
from collections import OrderedDict
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
-import qtest
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu import qtest
# This will not work if arguments contain spaces but is necessary if we
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 64c6e27..002ded6 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,4 +1,4 @@
# Add Python module requirements, one per line, to be installed
# in the tests/venv Python virtual environment. For more info,
# refer to: https://pip.pypa.io/en/stable/user_guide/#id1
-avocado-framework==65.0
+avocado-framework==68.0
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index bdca6cb..0556bdc 100755
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -17,7 +17,7 @@ import sys
import logging
import time
import datetime
-sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import QEMUMachine, kvm_available
import subprocess
import hashlib