xref: /qemu/tests/qtest/libqos/libqos.c (revision 907b5105)
11cf4323eSThomas Huth #include "qemu/osdep.h"
21cf4323eSThomas Huth #include <sys/wait.h>
31cf4323eSThomas Huth 
4*907b5105SMarc-André Lureau #include "../libqtest.h"
5a2ce7dbdSPaolo Bonzini #include "libqos.h"
6a2ce7dbdSPaolo Bonzini #include "pci.h"
71cf4323eSThomas Huth #include "qapi/qmp/qdict.h"
81cf4323eSThomas Huth 
91cf4323eSThomas Huth /*** Test Setup & Teardown ***/
101cf4323eSThomas Huth 
111cf4323eSThomas Huth /**
121cf4323eSThomas Huth  * Launch QEMU with the given command line,
131cf4323eSThomas Huth  * and then set up interrupts and our guest malloc interface.
141cf4323eSThomas Huth  * Never returns NULL:
151cf4323eSThomas Huth  * Terminates the application in case an error is encountered.
161cf4323eSThomas Huth  */
171cf4323eSThomas Huth QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
181cf4323eSThomas Huth {
191cf4323eSThomas Huth     char *cmdline;
201cf4323eSThomas Huth 
211cf4323eSThomas Huth     QOSState *qs = g_new0(QOSState, 1);
221cf4323eSThomas Huth 
231cf4323eSThomas Huth     cmdline = g_strdup_vprintf(cmdline_fmt, ap);
241cf4323eSThomas Huth     qs->qts = qtest_init(cmdline);
251cf4323eSThomas Huth     qs->ops = ops;
261cf4323eSThomas Huth     if (ops) {
271cf4323eSThomas Huth         ops->alloc_init(&qs->alloc, qs->qts, ALLOC_NO_FLAGS);
281cf4323eSThomas Huth         qs->pcibus = ops->qpci_new(qs->qts, &qs->alloc);
291cf4323eSThomas Huth     }
301cf4323eSThomas Huth 
311cf4323eSThomas Huth     g_free(cmdline);
321cf4323eSThomas Huth     return qs;
331cf4323eSThomas Huth }
341cf4323eSThomas Huth 
351cf4323eSThomas Huth /**
361cf4323eSThomas Huth  * Launch QEMU with the given command line,
371cf4323eSThomas Huth  * and then set up interrupts and our guest malloc interface.
381cf4323eSThomas Huth  */
391cf4323eSThomas Huth QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
401cf4323eSThomas Huth {
411cf4323eSThomas Huth     QOSState *qs;
421cf4323eSThomas Huth     va_list ap;
431cf4323eSThomas Huth 
441cf4323eSThomas Huth     va_start(ap, cmdline_fmt);
451cf4323eSThomas Huth     qs = qtest_vboot(ops, cmdline_fmt, ap);
461cf4323eSThomas Huth     va_end(ap);
471cf4323eSThomas Huth 
481cf4323eSThomas Huth     return qs;
491cf4323eSThomas Huth }
501cf4323eSThomas Huth 
511cf4323eSThomas Huth /**
521cf4323eSThomas Huth  * Tear down the QEMU instance.
531cf4323eSThomas Huth  */
541cf4323eSThomas Huth void qtest_common_shutdown(QOSState *qs)
551cf4323eSThomas Huth {
561cf4323eSThomas Huth     if (qs->ops) {
571cf4323eSThomas Huth         if (qs->pcibus && qs->ops->qpci_free) {
581cf4323eSThomas Huth             qs->ops->qpci_free(qs->pcibus);
591cf4323eSThomas Huth             qs->pcibus = NULL;
601cf4323eSThomas Huth         }
611cf4323eSThomas Huth     }
621cf4323eSThomas Huth     alloc_destroy(&qs->alloc);
631cf4323eSThomas Huth     qtest_quit(qs->qts);
641cf4323eSThomas Huth     g_free(qs);
651cf4323eSThomas Huth }
661cf4323eSThomas Huth 
671cf4323eSThomas Huth void qtest_shutdown(QOSState *qs)
681cf4323eSThomas Huth {
691cf4323eSThomas Huth     if (qs->ops && qs->ops->shutdown) {
701cf4323eSThomas Huth         qs->ops->shutdown(qs);
711cf4323eSThomas Huth     } else {
721cf4323eSThomas Huth         qtest_common_shutdown(qs);
731cf4323eSThomas Huth     }
741cf4323eSThomas Huth }
751cf4323eSThomas Huth 
761cf4323eSThomas Huth static QDict *qmp_execute(QTestState *qts, const char *command)
771cf4323eSThomas Huth {
781cf4323eSThomas Huth     return qtest_qmp(qts, "{ 'execute': %s }", command);
791cf4323eSThomas Huth }
801cf4323eSThomas Huth 
811cf4323eSThomas Huth void migrate(QOSState *from, QOSState *to, const char *uri)
821cf4323eSThomas Huth {
831cf4323eSThomas Huth     const char *st;
841cf4323eSThomas Huth     QDict *rsp, *sub;
851cf4323eSThomas Huth     bool running;
861cf4323eSThomas Huth 
871cf4323eSThomas Huth     /* Is the machine currently running? */
881cf4323eSThomas Huth     rsp = qmp_execute(from->qts, "query-status");
891cf4323eSThomas Huth     g_assert(qdict_haskey(rsp, "return"));
901cf4323eSThomas Huth     sub = qdict_get_qdict(rsp, "return");
911cf4323eSThomas Huth     g_assert(qdict_haskey(sub, "running"));
921cf4323eSThomas Huth     running = qdict_get_bool(sub, "running");
931cf4323eSThomas Huth     qobject_unref(rsp);
941cf4323eSThomas Huth 
951cf4323eSThomas Huth     /* Issue the migrate command. */
961cf4323eSThomas Huth     rsp = qtest_qmp(from->qts,
971cf4323eSThomas Huth                     "{ 'execute': 'migrate', 'arguments': { 'uri': %s }}",
981cf4323eSThomas Huth                     uri);
991cf4323eSThomas Huth     g_assert(qdict_haskey(rsp, "return"));
1001cf4323eSThomas Huth     qobject_unref(rsp);
1011cf4323eSThomas Huth 
1021cf4323eSThomas Huth     /* Wait for STOP event, but only if we were running: */
1031cf4323eSThomas Huth     if (running) {
1041cf4323eSThomas Huth         qtest_qmp_eventwait(from->qts, "STOP");
1051cf4323eSThomas Huth     }
1061cf4323eSThomas Huth 
1071cf4323eSThomas Huth     /* If we were running, we can wait for an event. */
1081cf4323eSThomas Huth     if (running) {
1091cf4323eSThomas Huth         migrate_allocator(&from->alloc, &to->alloc);
1101cf4323eSThomas Huth         qtest_qmp_eventwait(to->qts, "RESUME");
1111cf4323eSThomas Huth         return;
1121cf4323eSThomas Huth     }
1131cf4323eSThomas Huth 
1141cf4323eSThomas Huth     /* Otherwise, we need to wait: poll until migration is completed. */
1151cf4323eSThomas Huth     while (1) {
1161cf4323eSThomas Huth         rsp = qmp_execute(from->qts, "query-migrate");
1171cf4323eSThomas Huth         g_assert(qdict_haskey(rsp, "return"));
1181cf4323eSThomas Huth         sub = qdict_get_qdict(rsp, "return");
1191cf4323eSThomas Huth         g_assert(qdict_haskey(sub, "status"));
1201cf4323eSThomas Huth         st = qdict_get_str(sub, "status");
1211cf4323eSThomas Huth 
1221cf4323eSThomas Huth         /* "setup", "active", "completed", "failed", "cancelled" */
1231cf4323eSThomas Huth         if (strcmp(st, "completed") == 0) {
1241cf4323eSThomas Huth             qobject_unref(rsp);
1251cf4323eSThomas Huth             break;
1261cf4323eSThomas Huth         }
1271cf4323eSThomas Huth 
1281cf4323eSThomas Huth         if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)
1291cf4323eSThomas Huth             || (strcmp(st, "wait-unplug") == 0)) {
1301cf4323eSThomas Huth             qobject_unref(rsp);
1311cf4323eSThomas Huth             g_usleep(5000);
1321cf4323eSThomas Huth             continue;
1331cf4323eSThomas Huth         }
1341cf4323eSThomas Huth 
1351cf4323eSThomas Huth         fprintf(stderr, "Migration did not complete, status: %s\n", st);
1361cf4323eSThomas Huth         g_assert_not_reached();
1371cf4323eSThomas Huth     }
1381cf4323eSThomas Huth 
1391cf4323eSThomas Huth     migrate_allocator(&from->alloc, &to->alloc);
1401cf4323eSThomas Huth }
1411cf4323eSThomas Huth 
1421cf4323eSThomas Huth bool have_qemu_img(void)
1431cf4323eSThomas Huth {
1441cf4323eSThomas Huth     char *rpath;
1451cf4323eSThomas Huth     const char *path = getenv("QTEST_QEMU_IMG");
1461cf4323eSThomas Huth     if (!path) {
1471cf4323eSThomas Huth         return false;
1481cf4323eSThomas Huth     }
1491cf4323eSThomas Huth 
1501cf4323eSThomas Huth     rpath = realpath(path, NULL);
1511cf4323eSThomas Huth     if (!rpath) {
1521cf4323eSThomas Huth         return false;
1531cf4323eSThomas Huth     } else {
1541cf4323eSThomas Huth         free(rpath);
1551cf4323eSThomas Huth         return true;
1561cf4323eSThomas Huth     }
1571cf4323eSThomas Huth }
1581cf4323eSThomas Huth 
1591cf4323eSThomas Huth void mkimg(const char *file, const char *fmt, unsigned size_mb)
1601cf4323eSThomas Huth {
1611cf4323eSThomas Huth     gchar *cli;
1621cf4323eSThomas Huth     bool ret;
1631cf4323eSThomas Huth     int rc;
1641cf4323eSThomas Huth     GError *err = NULL;
1651cf4323eSThomas Huth     char *qemu_img_path;
1661cf4323eSThomas Huth     gchar *out, *out2;
1671cf4323eSThomas Huth     char *qemu_img_abs_path;
1681cf4323eSThomas Huth 
1691cf4323eSThomas Huth     qemu_img_path = getenv("QTEST_QEMU_IMG");
1701cf4323eSThomas Huth     g_assert(qemu_img_path);
1711cf4323eSThomas Huth     qemu_img_abs_path = realpath(qemu_img_path, NULL);
1721cf4323eSThomas Huth     g_assert(qemu_img_abs_path);
1731cf4323eSThomas Huth 
1741cf4323eSThomas Huth     cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path,
1751cf4323eSThomas Huth                           fmt, file, size_mb);
1761cf4323eSThomas Huth     ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err);
1771cf4323eSThomas Huth     if (err || !g_spawn_check_exit_status(rc, &err)) {
1781cf4323eSThomas Huth         fprintf(stderr, "%s\n", err->message);
1791cf4323eSThomas Huth         g_error_free(err);
1801cf4323eSThomas Huth     }
1811cf4323eSThomas Huth     g_assert(ret && !err);
1821cf4323eSThomas Huth 
1831cf4323eSThomas Huth     g_free(out);
1841cf4323eSThomas Huth     g_free(out2);
1851cf4323eSThomas Huth     g_free(cli);
1861cf4323eSThomas Huth     free(qemu_img_abs_path);
1871cf4323eSThomas Huth }
1881cf4323eSThomas Huth 
1891cf4323eSThomas Huth void mkqcow2(const char *file, unsigned size_mb)
1901cf4323eSThomas Huth {
1911cf4323eSThomas Huth     return mkimg(file, "qcow2", size_mb);
1921cf4323eSThomas Huth }
1931cf4323eSThomas Huth 
1941cf4323eSThomas Huth void prepare_blkdebug_script(const char *debug_fn, const char *event)
1951cf4323eSThomas Huth {
1961cf4323eSThomas Huth     FILE *debug_file = fopen(debug_fn, "w");
1971cf4323eSThomas Huth     int ret;
1981cf4323eSThomas Huth 
1991cf4323eSThomas Huth     fprintf(debug_file, "[inject-error]\n");
2001cf4323eSThomas Huth     fprintf(debug_file, "event = \"%s\"\n", event);
2011cf4323eSThomas Huth     fprintf(debug_file, "errno = \"5\"\n");
2021cf4323eSThomas Huth     fprintf(debug_file, "state = \"1\"\n");
2031cf4323eSThomas Huth     fprintf(debug_file, "immediately = \"off\"\n");
2041cf4323eSThomas Huth     fprintf(debug_file, "once = \"on\"\n");
2051cf4323eSThomas Huth 
2061cf4323eSThomas Huth     fprintf(debug_file, "[set-state]\n");
2071cf4323eSThomas Huth     fprintf(debug_file, "event = \"%s\"\n", event);
2081cf4323eSThomas Huth     fprintf(debug_file, "new_state = \"2\"\n");
2091cf4323eSThomas Huth     fflush(debug_file);
2101cf4323eSThomas Huth     g_assert(!ferror(debug_file));
2111cf4323eSThomas Huth 
2121cf4323eSThomas Huth     ret = fclose(debug_file);
2131cf4323eSThomas Huth     g_assert(ret == 0);
2141cf4323eSThomas Huth }
2151cf4323eSThomas Huth 
2161cf4323eSThomas Huth void generate_pattern(void *buffer, size_t len, size_t cycle_len)
2171cf4323eSThomas Huth {
2181cf4323eSThomas Huth     int i, j;
2191cf4323eSThomas Huth     unsigned char *tx = (unsigned char *)buffer;
2201cf4323eSThomas Huth     unsigned char p;
2211cf4323eSThomas Huth     size_t *sx;
2221cf4323eSThomas Huth 
2231cf4323eSThomas Huth     /* Write an indicative pattern that varies and is unique per-cycle */
2241cf4323eSThomas Huth     p = rand() % 256;
2251cf4323eSThomas Huth     for (i = 0; i < len; i++) {
2261cf4323eSThomas Huth         tx[i] = p++ % 256;
2271cf4323eSThomas Huth         if (i % cycle_len == 0) {
2281cf4323eSThomas Huth             p = rand() % 256;
2291cf4323eSThomas Huth         }
2301cf4323eSThomas Huth     }
2311cf4323eSThomas Huth 
2321cf4323eSThomas Huth     /* force uniqueness by writing an id per-cycle */
2331cf4323eSThomas Huth     for (i = 0; i < len / cycle_len; i++) {
2341cf4323eSThomas Huth         j = i * cycle_len;
2351cf4323eSThomas Huth         if (j + sizeof(*sx) <= len) {
2361cf4323eSThomas Huth             sx = (size_t *)&tx[j];
2371cf4323eSThomas Huth             *sx = i;
2381cf4323eSThomas Huth         }
2391cf4323eSThomas Huth     }
2401cf4323eSThomas Huth }
241