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 | ||||
| { | ||||
|     int fd; | ||||
|     int qmp_fd; | ||||
|     bool irq_level[MAX_IRQ]; | ||||
|     GString *rx; | ||||
|     gchar *pid_file; | ||||
| @ -45,25 +46,11 @@ struct QTestState | ||||
|     g_assert_cmpint(ret, !=, -1); \ | ||||
| } while (0) | ||||
| 
 | ||||
| QTestState *qtest_init(const char *extra_args) | ||||
| static int init_socket(const char *socket_path) | ||||
| { | ||||
|     QTestState *s; | ||||
|     struct sockaddr_un addr; | ||||
|     int sock, ret, i; | ||||
|     gchar *socket_path; | ||||
|     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)); | ||||
|     int sock; | ||||
|     int ret; | ||||
| 
 | ||||
|     sock = socket(PF_UNIX, SOCK_STREAM, 0); | ||||
|     g_assert_no_errno(sock); | ||||
| @ -78,21 +65,14 @@ QTestState *qtest_init(const char *extra_args) | ||||
|     g_assert_no_errno(ret); | ||||
|     listen(sock, 1); | ||||
| 
 | ||||
|     pid = fork(); | ||||
|     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 ?: ""); | ||||
|     return sock; | ||||
| } | ||||
| 
 | ||||
|         ret = system(command); | ||||
|         exit(ret); | ||||
|         g_free(command); | ||||
|     } | ||||
| static int socket_accept(int sock) | ||||
| { | ||||
|     struct sockaddr_un addr; | ||||
|     socklen_t addrlen; | ||||
|     int ret; | ||||
| 
 | ||||
|     do { | ||||
|         ret = accept(sock, (struct sockaddr *)&addr, &addrlen); | ||||
| @ -100,7 +80,52 @@ QTestState *qtest_init(const char *extra_args) | ||||
|     g_assert_no_errno(ret); | ||||
|     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->pid_file = pid_file; | ||||
|     for (i = 0; i < MAX_IRQ; i++) { | ||||
| @ -108,6 +133,11 @@ QTestState *qtest_init(const char *extra_args) | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
| } | ||||
| @ -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; | ||||
|     size_t size, offset; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     str = g_strdup_vprintf(fmt, ap); | ||||
|     va_end(ap); | ||||
|     size = strlen(str); | ||||
| 
 | ||||
|     offset = 0; | ||||
|     while (offset < size) { | ||||
|         ssize_t len; | ||||
| 
 | ||||
|         len = write(s->fd, str + offset, size - offset); | ||||
|         len = write(fd, str + offset, size - offset); | ||||
|         if (len == -1 && errno == EINTR) { | ||||
|             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) | ||||
| { | ||||
|     GString *line; | ||||
| @ -233,6 +269,39 @@ redo: | ||||
|     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 *qemu = getenv("QTEST_QEMU_BINARY"); | ||||
|  | ||||
| @ -37,6 +37,15 @@ QTestState *qtest_init(const char *extra_args); | ||||
|  */ | ||||
| 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: | ||||
|  * @s: QTestState instance to operate on. | ||||
| @ -206,6 +215,14 @@ void qtest_add_func(const char *str, void (*fn)); | ||||
|     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: | ||||
|  * @num: Interrupt to observe. | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Kevin Wolf
						Kevin Wolf