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