mirror of
https://git.proxmox.com/git/qemu
synced 2025-06-28 19:42:41 +00:00
qtest: Add function to send QMP commands
Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
c68b039aa9
commit
a3ca163cb5
143
tests/libqtest.c
143
tests/libqtest.c
@ -36,6 +36,7 @@ QTestState *global_qtest;
|
|||||||
struct QTestState
|
struct QTestState
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
int qmp_fd;
|
||||||
bool irq_level[MAX_IRQ];
|
bool irq_level[MAX_IRQ];
|
||||||
GString *rx;
|
GString *rx;
|
||||||
gchar *pid_file;
|
gchar *pid_file;
|
||||||
@ -45,25 +46,11 @@ struct QTestState
|
|||||||
g_assert_cmpint(ret, !=, -1); \
|
g_assert_cmpint(ret, !=, -1); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
QTestState *qtest_init(const char *extra_args)
|
static int init_socket(const char *socket_path)
|
||||||
{
|
{
|
||||||
QTestState *s;
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
int sock, ret, i;
|
int sock;
|
||||||
gchar *socket_path;
|
int ret;
|
||||||
gchar *pid_file;
|
|
||||||
gchar *command;
|
|
||||||
const char *qemu_binary;
|
|
||||||
pid_t pid;
|
|
||||||
socklen_t addrlen;
|
|
||||||
|
|
||||||
qemu_binary = getenv("QTEST_QEMU_BINARY");
|
|
||||||
g_assert(qemu_binary != NULL);
|
|
||||||
|
|
||||||
socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
|
|
||||||
pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
|
|
||||||
|
|
||||||
s = g_malloc(sizeof(*s));
|
|
||||||
|
|
||||||
sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
sock = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
g_assert_no_errno(sock);
|
g_assert_no_errno(sock);
|
||||||
@ -78,21 +65,14 @@ QTestState *qtest_init(const char *extra_args)
|
|||||||
g_assert_no_errno(ret);
|
g_assert_no_errno(ret);
|
||||||
listen(sock, 1);
|
listen(sock, 1);
|
||||||
|
|
||||||
pid = fork();
|
return sock;
|
||||||
if (pid == 0) {
|
}
|
||||||
command = g_strdup_printf("%s "
|
|
||||||
"-qtest unix:%s,nowait "
|
|
||||||
"-qtest-log /dev/null "
|
|
||||||
"-pidfile %s "
|
|
||||||
"-machine accel=qtest "
|
|
||||||
"%s", qemu_binary, socket_path,
|
|
||||||
pid_file,
|
|
||||||
extra_args ?: "");
|
|
||||||
|
|
||||||
ret = system(command);
|
static int socket_accept(int sock)
|
||||||
exit(ret);
|
{
|
||||||
g_free(command);
|
struct sockaddr_un addr;
|
||||||
}
|
socklen_t addrlen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
|
ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
|
||||||
@ -100,7 +80,52 @@ QTestState *qtest_init(const char *extra_args)
|
|||||||
g_assert_no_errno(ret);
|
g_assert_no_errno(ret);
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
s->fd = ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTestState *qtest_init(const char *extra_args)
|
||||||
|
{
|
||||||
|
QTestState *s;
|
||||||
|
int sock, qmpsock, ret, i;
|
||||||
|
gchar *socket_path;
|
||||||
|
gchar *qmp_socket_path;
|
||||||
|
gchar *pid_file;
|
||||||
|
gchar *command;
|
||||||
|
const char *qemu_binary;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
qemu_binary = getenv("QTEST_QEMU_BINARY");
|
||||||
|
g_assert(qemu_binary != NULL);
|
||||||
|
|
||||||
|
socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
|
||||||
|
qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
|
||||||
|
pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
|
||||||
|
|
||||||
|
s = g_malloc(sizeof(*s));
|
||||||
|
|
||||||
|
sock = init_socket(socket_path);
|
||||||
|
qmpsock = init_socket(qmp_socket_path);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
command = g_strdup_printf("%s "
|
||||||
|
"-qtest unix:%s,nowait "
|
||||||
|
"-qtest-log /dev/null "
|
||||||
|
"-qmp unix:%s,nowait "
|
||||||
|
"-pidfile %s "
|
||||||
|
"-machine accel=qtest "
|
||||||
|
"%s", qemu_binary, socket_path,
|
||||||
|
qmp_socket_path, pid_file,
|
||||||
|
extra_args ?: "");
|
||||||
|
|
||||||
|
ret = system(command);
|
||||||
|
exit(ret);
|
||||||
|
g_free(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->fd = socket_accept(sock);
|
||||||
|
s->qmp_fd = socket_accept(qmpsock);
|
||||||
|
|
||||||
s->rx = g_string_new("");
|
s->rx = g_string_new("");
|
||||||
s->pid_file = pid_file;
|
s->pid_file = pid_file;
|
||||||
for (i = 0; i < MAX_IRQ; i++) {
|
for (i = 0; i < MAX_IRQ; i++) {
|
||||||
@ -108,6 +133,11 @@ QTestState *qtest_init(const char *extra_args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_free(socket_path);
|
g_free(socket_path);
|
||||||
|
g_free(qmp_socket_path);
|
||||||
|
|
||||||
|
/* Read the QMP greeting and then do the handshake */
|
||||||
|
qtest_qmp(s, "");
|
||||||
|
qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }");
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -131,22 +161,19 @@ void qtest_quit(QTestState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
|
static void socket_sendf(int fd, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
va_list ap;
|
|
||||||
gchar *str;
|
gchar *str;
|
||||||
size_t size, offset;
|
size_t size, offset;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
str = g_strdup_vprintf(fmt, ap);
|
str = g_strdup_vprintf(fmt, ap);
|
||||||
va_end(ap);
|
|
||||||
size = strlen(str);
|
size = strlen(str);
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
while (offset < size) {
|
while (offset < size) {
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
len = write(s->fd, str + offset, size - offset);
|
len = write(fd, str + offset, size - offset);
|
||||||
if (len == -1 && errno == EINTR) {
|
if (len == -1 && errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -158,6 +185,15 @@ static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
socket_sendf(s->fd, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
static GString *qtest_recv_line(QTestState *s)
|
static GString *qtest_recv_line(QTestState *s)
|
||||||
{
|
{
|
||||||
GString *line;
|
GString *line;
|
||||||
@ -233,6 +269,39 @@ redo:
|
|||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qtest_qmp(QTestState *s, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
bool has_reply = false;
|
||||||
|
int nesting = 0;
|
||||||
|
|
||||||
|
/* Send QMP request */
|
||||||
|
va_start(ap, fmt);
|
||||||
|
socket_sendf(s->qmp_fd, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/* Receive reply */
|
||||||
|
while (!has_reply || nesting > 0) {
|
||||||
|
ssize_t len;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
len = read(s->qmp_fd, &c, 1);
|
||||||
|
if (len == -1 && errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '{':
|
||||||
|
nesting++;
|
||||||
|
has_reply = true;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
nesting--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *qtest_get_arch(void)
|
const char *qtest_get_arch(void)
|
||||||
{
|
{
|
||||||
const char *qemu = getenv("QTEST_QEMU_BINARY");
|
const char *qemu = getenv("QTEST_QEMU_BINARY");
|
||||||
|
@ -37,6 +37,15 @@ QTestState *qtest_init(const char *extra_args);
|
|||||||
*/
|
*/
|
||||||
void qtest_quit(QTestState *s);
|
void qtest_quit(QTestState *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qtest_qmp:
|
||||||
|
* @s: QTestState instance to operate on.
|
||||||
|
* @fmt...: QMP message to send to qemu
|
||||||
|
*
|
||||||
|
* Sends a QMP message to QEMU
|
||||||
|
*/
|
||||||
|
void qtest_qmp(QTestState *s, const char *fmt, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qtest_get_irq:
|
* qtest_get_irq:
|
||||||
* @s: QTestState instance to operate on.
|
* @s: QTestState instance to operate on.
|
||||||
@ -206,6 +215,14 @@ void qtest_add_func(const char *str, void (*fn));
|
|||||||
global_qtest = qtest_init((args)) \
|
global_qtest = qtest_init((args)) \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qmp:
|
||||||
|
* @fmt...: QMP message to send to qemu
|
||||||
|
*
|
||||||
|
* Sends a QMP message to QEMU
|
||||||
|
*/
|
||||||
|
#define qmp(fmt, ...) qtest_qmp(global_qtest, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get_irq:
|
* get_irq:
|
||||||
* @num: Interrupt to observe.
|
* @num: Interrupt to observe.
|
||||||
|
Loading…
Reference in New Issue
Block a user