1 # Test class and utilities for functional tests
3 # Copyright (c) 2018 Red Hat, Inc.
6 # Cleber Rosa <crosa@redhat.com>
8 # This work is licensed under the terms of the GNU GPL, version 2 or
9 # later. See the COPYING file in the top-level directory.
19 SRC_ROOT_DIR
= os
.path
.join(os
.path
.dirname(__file__
), '..', '..', '..')
20 sys
.path
.append(os
.path
.join(SRC_ROOT_DIR
, 'python'))
22 from qemu
.machine
import QEMUMachine
24 def is_readable_executable_file(path
):
25 return os
.path
.isfile(path
) and os
.access(path
, os
.R_OK | os
.X_OK
)
28 def pick_default_qemu_bin(arch
=None):
30 Picks the path of a QEMU binary, starting either in the current working
31 directory or in the source tree root directory.
33 :param arch: the arch to use when looking for a QEMU binary (the target
34 will match the arch given). If None (the default), arch
35 will be the current host system arch (as given by
38 :returns: the path to the default QEMU binary or None if one could not
44 # qemu binary path does not match arch for powerpc, handle it
47 qemu_bin_relative_path
= os
.path
.join("%s-softmmu" % arch
,
48 "qemu-system-%s" % arch
)
49 if is_readable_executable_file(qemu_bin_relative_path
):
50 return qemu_bin_relative_path
52 qemu_bin_from_src_dir_path
= os
.path
.join(SRC_ROOT_DIR
,
53 qemu_bin_relative_path
)
54 if is_readable_executable_file(qemu_bin_from_src_dir_path
):
55 return qemu_bin_from_src_dir_path
58 def wait_for_console_pattern(test
, success_message
, failure_message
=None):
60 Waits for messages to appear on the console, while logging the content
62 :param test: an Avocado test containing a VM that will have its console
63 read and probed for a success or failure message
64 :type test: :class:`avocado_qemu.Test`
65 :param success_message: if this message appears, test succeeds
66 :param failure_message: if this message appears, test fails
68 console
= test
.vm
.console_socket
.makefile()
69 console_logger
= logging
.getLogger('console')
71 msg
= console
.readline().strip()
74 console_logger
.debug(msg
)
75 if success_message
in msg
:
77 if failure_message
and failure_message
in msg
:
79 fail
= 'Failure message found in console: %s' % failure_message
83 def exec_command_and_wait_for_pattern(test
, command
,
84 success_message
, failure_message
=None):
86 Send a command to a console (appending CRLF characters), then wait
87 for success_message to appear on the console, while logging the.
88 content. Mark the test as failed if failure_message is found instead.
90 :param test: an Avocado test containing a VM that will have its console
91 read and probed for a success or failure message
92 :type test: :class:`avocado_qemu.Test`
93 :param command: the command to send
94 :param success_message: if this message appears, test succeeds
95 :param failure_message: if this message appears, test fails
98 test
.vm
.console_socket
.sendall(command
.encode())
99 wait_for_console_pattern(test
, success_message
, failure_message
)
102 class Test(avocado
.Test
):
103 def _get_unique_tag_val(self
, tag_name
):
105 Gets a tag value, if unique for a key
107 vals
= self
.tags
.get(tag_name
, [])
115 self
.arch
= self
.params
.get('arch',
116 default
=self
._get
_unique
_tag
_val
('arch'))
118 self
.machine
= self
.params
.get('machine',
119 default
=self
._get
_unique
_tag
_val
('machine'))
121 default_qemu_bin
= pick_default_qemu_bin(arch
=self
.arch
)
122 self
.qemu_bin
= self
.params
.get('qemu_bin',
123 default
=default_qemu_bin
)
124 if self
.qemu_bin
is None:
125 self
.cancel("No QEMU binary defined or found in the source tree")
127 def _new_vm(self
, *args
):
128 vm
= QEMUMachine(self
.qemu_bin
, sock_dir
=tempfile
.mkdtemp())
135 return self
.get_vm(name
='default')
137 def get_vm(self
, *args
, name
=None):
139 name
= str(uuid
.uuid4())
140 if self
._vms
.get(name
) is None:
141 self
._vms
[name
] = self
._new
_vm
(*args
)
142 if self
.machine
is not None:
143 self
._vms
[name
].set_machine(self
.machine
)
144 return self
._vms
[name
]
147 for vm
in self
._vms
.values():