backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / qemumonitortestutils.c
blob4cc07b877200caa78a15da1b9901f94362539dd8
1 /*
2 * Copyright (C) 2011-2013 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
20 #include <config.h>
22 #include <time.h>
24 #include "testutils.h"
25 #include "testutilsqemuschema.h"
26 #include "qemumonitortestutils.h"
28 #include "virthread.h"
29 #define LIBVIRT_QEMU_PROCESSPRIV_H_ALLOW
30 #include "qemu/qemu_processpriv.h"
31 #include "qemu/qemu_monitor.h"
32 #include "qemu/qemu_agent.h"
33 #include "qemu/qemu_qapi.h"
34 #include "rpc/virnetsocket.h"
35 #include "viralloc.h"
36 #include "virlog.h"
37 #include "virerror.h"
38 #include "virstring.h"
40 #define VIR_FROM_THIS VIR_FROM_NONE
42 VIR_LOG_INIT("tests.qemumonitortestutils");
44 struct _qemuMonitorTestItem {
45 qemuMonitorTestResponseCallback cb;
46 void *opaque;
47 virFreeCallback freecb;
50 struct _qemuMonitorTest {
51 virMutex lock;
52 virThread thread;
54 bool quit;
55 bool running;
56 bool started;
58 char *incoming;
59 size_t incomingLength;
60 size_t incomingCapacity;
62 char *outgoing;
63 size_t outgoingLength;
64 size_t outgoingCapacity;
66 virNetSocketPtr server;
67 virNetSocketPtr client;
69 qemuMonitorPtr mon;
70 qemuAgentPtr agent;
72 char *tmpdir;
74 size_t nitems;
75 qemuMonitorTestItemPtr *items;
77 virDomainObjPtr vm;
78 virHashTablePtr qapischema;
82 static void
83 qemuMonitorTestItemFree(qemuMonitorTestItemPtr item)
85 if (!item)
86 return;
88 if (item->freecb)
89 (item->freecb)(item->opaque);
91 VIR_FREE(item);
96 * Appends data for a reply to the outgoing buffer
98 int
99 qemuMonitorTestAddResponse(qemuMonitorTestPtr test,
100 const char *response)
102 size_t want = strlen(response) + 2;
103 size_t have = test->outgoingCapacity - test->outgoingLength;
105 VIR_DEBUG("Adding response to monitor command: '%s", response);
107 if (have < want) {
108 size_t need = want - have;
109 if (VIR_EXPAND_N(test->outgoing, test->outgoingCapacity, need) < 0)
110 return -1;
113 want -= 2;
114 memcpy(test->outgoing + test->outgoingLength, response, want);
115 memcpy(test->outgoing + test->outgoingLength + want, "\r\n", 2);
116 test->outgoingLength += want + 2;
117 return 0;
121 static int
122 qemuMonitorTestAddErrorResponse(qemuMonitorTestPtr test,
123 const char *usermsg)
125 virBuffer buf = VIR_BUFFER_INITIALIZER;
126 VIR_AUTOFREE(char *) escapemsg = NULL;
127 VIR_AUTOFREE(char *) jsonmsg = NULL;
128 char *tmp;
130 if (!usermsg)
131 usermsg = "unexpected command";
133 virBufferEscape(&buf, '\\', "\"", "%s", usermsg);
134 if (virBufferCheckError(&buf) < 0)
135 return -1;
136 escapemsg = virBufferContentAndReset(&buf);
138 /* replace newline/carriage return with space */
139 tmp = escapemsg;
140 while (*tmp) {
141 if (*tmp == '\r' || *tmp == '\n')
142 *tmp = ' ';
144 tmp++;
147 /* format the JSON error message */
148 if (virAsprintf(&jsonmsg, "{ \"error\": "
149 " { \"desc\": \"%s\", "
150 " \"class\": \"UnexpectedCommand\" } }",
151 escapemsg) < 0)
152 return -1;
154 return qemuMonitorTestAddResponse(test, jsonmsg);
158 static int
159 qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test,
160 const char *command)
162 VIR_AUTOFREE(char *) msg = NULL;
164 if (virAsprintf(&msg, "unexpected command: '%s'", command) < 0)
165 return -1;
167 return qemuMonitorTestAddErrorResponse(test, msg);
172 qemuMonitorTestAddInvalidCommandResponse(qemuMonitorTestPtr test,
173 const char *expectedcommand,
174 const char *actualcommand)
176 VIR_AUTOFREE(char *) msg = NULL;
178 if (virAsprintf(&msg, "expected command '%s' got '%s'",
179 expectedcommand, actualcommand) < 0)
180 return -1;
182 return qemuMonitorTestAddErrorResponse(test, msg);
186 int ATTRIBUTE_FMT_PRINTF(2, 3)
187 qemuMonitorReportError(qemuMonitorTestPtr test, const char *errmsg, ...)
189 va_list msgargs;
190 VIR_AUTOFREE(char *) tmp = NULL;
191 VIR_AUTOFREE(char *) msg = NULL;
192 VIR_AUTOFREE(char *) jsonmsg = NULL;
193 int ret = -1;
195 va_start(msgargs, errmsg);
197 if (virVasprintf(&msg, errmsg, msgargs) < 0)
198 goto cleanup;
200 if (!(tmp = qemuMonitorEscapeArg(msg)))
201 goto cleanup;
203 if (virAsprintf(&jsonmsg, "{ \"error\": "
204 " { \"desc\": \"%s\", "
205 " \"class\": \"UnexpectedCommand\" } }",
206 tmp) < 0)
207 goto cleanup;
209 ret = qemuMonitorTestAddResponse(test, jsonmsg);
211 cleanup:
212 va_end(msgargs);
213 return ret;
217 static int
218 qemuMonitorTestProcessCommand(qemuMonitorTestPtr test,
219 const char *cmdstr)
221 int ret;
223 VIR_DEBUG("Processing string from monitor handler: '%s", cmdstr);
225 if (test->nitems == 0) {
226 return qemuMonitorTestAddUnexpectedErrorResponse(test, cmdstr);
227 } else {
228 qemuMonitorTestItemPtr item = test->items[0];
229 ret = (item->cb)(test, item, cmdstr);
230 qemuMonitorTestItemFree(item);
231 if (VIR_DELETE_ELEMENT(test->items, 0, test->nitems) < 0)
232 return -1;
235 return ret;
240 * Handles read/write of monitor data on the monitor server side
242 static void
243 qemuMonitorTestIO(virNetSocketPtr sock,
244 int events,
245 void *opaque)
247 qemuMonitorTestPtr test = opaque;
248 bool err = false;
250 virMutexLock(&test->lock);
251 if (test->quit) {
252 virMutexUnlock(&test->lock);
253 return;
255 if (events & VIR_EVENT_HANDLE_WRITABLE) {
256 ssize_t ret;
257 if ((ret = virNetSocketWrite(sock,
258 test->outgoing,
259 test->outgoingLength)) < 0) {
260 err = true;
261 goto cleanup;
264 memmove(test->outgoing,
265 test->outgoing + ret,
266 test->outgoingLength - ret);
267 test->outgoingLength -= ret;
269 if ((test->outgoingCapacity - test->outgoingLength) > 1024)
270 VIR_SHRINK_N(test->outgoing, test->outgoingCapacity, 1024);
273 if (events & VIR_EVENT_HANDLE_READABLE) {
274 ssize_t ret, used;
275 char *t1, *t2;
277 if ((test->incomingCapacity - test->incomingLength) < 1024) {
278 if (VIR_EXPAND_N(test->incoming, test->incomingCapacity, 1024) < 0) {
279 err = true;
280 goto cleanup;
284 if ((ret = virNetSocketRead(sock,
285 test->incoming + test->incomingLength,
286 (test->incomingCapacity - test->incomingLength) - 1)) < 0) {
287 err = true;
288 goto cleanup;
290 test->incomingLength += ret;
291 test->incoming[test->incomingLength] = '\0';
293 /* Look to see if we've got a complete line, and
294 * if so, handle that command
296 t1 = test->incoming;
297 while ((t2 = strstr(t1, "\n")) ||
298 (test->agent && (t2 = strstr(t1, "\r")))) {
299 *t2 = '\0';
301 if (qemuMonitorTestProcessCommand(test, t1) < 0) {
302 err = true;
303 goto cleanup;
306 t1 = t2 + 1;
308 used = t1 - test->incoming;
309 memmove(test->incoming, t1, test->incomingLength - used);
310 test->incomingLength -= used;
311 if ((test->incomingCapacity - test->incomingLength) > 1024) {
312 VIR_SHRINK_N(test->incoming,
313 test->incomingCapacity,
314 1024);
318 if (events & (VIR_EVENT_HANDLE_HANGUP |
319 VIR_EVENT_HANDLE_ERROR))
320 err = true;
322 cleanup:
323 if (err) {
324 virNetSocketRemoveIOCallback(sock);
325 virNetSocketClose(sock);
326 virObjectUnref(test->client);
327 test->client = NULL;
328 } else {
329 events = VIR_EVENT_HANDLE_READABLE;
331 if (test->outgoingLength)
332 events |= VIR_EVENT_HANDLE_WRITABLE;
334 virNetSocketUpdateIOCallback(sock, events);
336 virMutexUnlock(&test->lock);
340 static void
341 qemuMonitorTestWorker(void *opaque)
343 qemuMonitorTestPtr test = opaque;
345 virMutexLock(&test->lock);
347 while (!test->quit) {
348 virMutexUnlock(&test->lock);
350 if (virEventRunDefaultImpl() < 0) {
351 virMutexLock(&test->lock);
352 test->quit = true;
353 break;
356 virMutexLock(&test->lock);
359 test->running = false;
361 virMutexUnlock(&test->lock);
362 return;
366 static void
367 qemuMonitorTestFreeTimer(int timer ATTRIBUTE_UNUSED,
368 void *opaque ATTRIBUTE_UNUSED)
370 /* nothing to be done here */
374 void
375 qemuMonitorTestFree(qemuMonitorTestPtr test)
377 size_t i;
378 int timer = -1;
380 if (!test)
381 return;
383 virMutexLock(&test->lock);
384 if (test->running) {
385 test->quit = true;
386 /* HACK: Add a dummy timeout to break event loop */
387 timer = virEventAddTimeout(0, qemuMonitorTestFreeTimer, NULL, NULL);
389 virMutexUnlock(&test->lock);
391 if (test->client) {
392 virNetSocketRemoveIOCallback(test->client);
393 virNetSocketClose(test->client);
394 virObjectUnref(test->client);
397 virObjectUnref(test->server);
398 if (test->mon) {
399 virObjectUnlock(test->mon);
400 qemuMonitorClose(test->mon);
403 if (test->agent) {
404 virObjectUnlock(test->agent);
405 qemuAgentClose(test->agent);
408 virObjectUnref(test->vm);
410 if (test->started)
411 virThreadJoin(&test->thread);
413 if (timer != -1)
414 virEventRemoveTimeout(timer);
416 VIR_FREE(test->incoming);
417 VIR_FREE(test->outgoing);
419 for (i = 0; i < test->nitems; i++)
420 qemuMonitorTestItemFree(test->items[i]);
421 VIR_FREE(test->items);
423 if (test->tmpdir && rmdir(test->tmpdir) < 0)
424 VIR_WARN("Failed to remove tempdir: %s", strerror(errno));
426 VIR_FREE(test->tmpdir);
428 virMutexDestroy(&test->lock);
429 VIR_FREE(test);
434 qemuMonitorTestAddHandler(qemuMonitorTestPtr test,
435 qemuMonitorTestResponseCallback cb,
436 void *opaque,
437 virFreeCallback freecb)
439 qemuMonitorTestItemPtr item;
441 if (VIR_ALLOC(item) < 0)
442 goto error;
444 item->cb = cb;
445 item->freecb = freecb;
446 item->opaque = opaque;
448 virMutexLock(&test->lock);
449 if (VIR_APPEND_ELEMENT(test->items, test->nitems, item) < 0) {
450 virMutexUnlock(&test->lock);
451 goto error;
453 virMutexUnlock(&test->lock);
455 return 0;
457 error:
458 if (freecb)
459 (freecb)(opaque);
460 VIR_FREE(item);
461 return -1;
464 void *
465 qemuMonitorTestItemGetPrivateData(qemuMonitorTestItemPtr item)
467 return item ? item->opaque : NULL;
471 typedef struct _qemuMonitorTestCommandArgs qemuMonitorTestCommandArgs;
472 typedef qemuMonitorTestCommandArgs *qemuMonitorTestCommandArgsPtr;
473 struct _qemuMonitorTestCommandArgs {
474 char *argname;
475 char *argval;
479 struct qemuMonitorTestHandlerData {
480 char *command_name;
481 char *cmderr;
482 char *response;
483 size_t nargs;
484 qemuMonitorTestCommandArgsPtr args;
485 char *expectArgs;
488 static void
489 qemuMonitorTestHandlerDataFree(void *opaque)
491 struct qemuMonitorTestHandlerData *data = opaque;
492 size_t i;
494 if (!data)
495 return;
497 for (i = 0; i < data->nargs; i++) {
498 VIR_FREE(data->args[i].argname);
499 VIR_FREE(data->args[i].argval);
502 VIR_FREE(data->command_name);
503 VIR_FREE(data->cmderr);
504 VIR_FREE(data->response);
505 VIR_FREE(data->args);
506 VIR_FREE(data->expectArgs);
507 VIR_FREE(data);
511 /* Returns -1 on error, 0 if validation was successful/not necessary, 1 if
512 * the validation has failed, and the reply was properly constructed */
513 static int
514 qemuMonitorTestProcessCommandDefaultValidate(qemuMonitorTestPtr test,
515 const char *cmdname,
516 virJSONValuePtr args)
518 VIR_AUTOCLEAN(virBuffer) debug = VIR_BUFFER_INITIALIZER;
519 virJSONValuePtr schemaroot;
520 VIR_AUTOPTR(virJSONValue) emptyargs = NULL;
521 VIR_AUTOFREE(char *) schemapath = NULL;
523 if (!test->qapischema)
524 return 0;
526 if (test->agent) {
527 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
528 "Command validation testing is not "
529 "implemented for the guest agent");
530 return -1;
533 /* 'device_add' needs to be skipped as it does not have fully defined schema */
534 if (STREQ(cmdname, "device_add"))
535 return 0;
537 if (virAsprintf(&schemapath, "%s/arg-type", cmdname) < 0)
538 return -1;
540 if (virQEMUQAPISchemaPathGet(schemapath, test->qapischema, &schemaroot) < 0 ||
541 !schemaroot) {
542 if (qemuMonitorReportError(test,
543 "command '%s' not found in QAPI schema",
544 cmdname) == 0)
545 return 1;
546 return -1;
549 if (!args) {
550 if (!(emptyargs = virJSONValueNewObject()))
551 return -1;
553 args = emptyargs;
556 if (testQEMUSchemaValidate(args, schemaroot, test->qapischema, &debug) < 0) {
557 if (qemuMonitorReportError(test,
558 "failed to validate arguments of '%s' "
559 "against QAPI schema: %s",
560 cmdname, virBufferCurrentContent(&debug)) == 0)
561 return 1;
562 return -1;
565 return 0;
569 static int
570 qemuMonitorTestProcessCommandDefault(qemuMonitorTestPtr test,
571 qemuMonitorTestItemPtr item,
572 const char *cmdstr)
574 struct qemuMonitorTestHandlerData *data = item->opaque;
575 VIR_AUTOPTR(virJSONValue) val = NULL;
576 virJSONValuePtr cmdargs = NULL;
577 const char *cmdname;
578 int rc;
580 if (!(val = virJSONValueFromString(cmdstr)))
581 return -1;
583 if (!(cmdname = virJSONValueObjectGetString(val, "execute")))
584 return qemuMonitorReportError(test, "Missing command name in %s", cmdstr);
586 cmdargs = virJSONValueObjectGet(val, "arguments");
587 if ((rc = qemuMonitorTestProcessCommandDefaultValidate(test, cmdname, cmdargs)) < 0)
588 return -1;
589 if (rc == 1)
590 return 0;
592 if (data->command_name && STRNEQ(data->command_name, cmdname)) {
593 return qemuMonitorTestAddInvalidCommandResponse(test, data->command_name,
594 cmdname);
595 } else {
596 return qemuMonitorTestAddResponse(test, data->response);
602 qemuMonitorTestAddItem(qemuMonitorTestPtr test,
603 const char *command_name,
604 const char *response)
606 struct qemuMonitorTestHandlerData *data;
608 if (VIR_ALLOC(data) < 0)
609 return -1;
611 if (VIR_STRDUP(data->command_name, command_name) < 0 ||
612 VIR_STRDUP(data->response, response) < 0) {
613 qemuMonitorTestHandlerDataFree(data);
614 return -1;
617 return qemuMonitorTestAddHandler(test,
618 qemuMonitorTestProcessCommandDefault,
619 data, qemuMonitorTestHandlerDataFree);
623 static int
624 qemuMonitorTestProcessCommandVerbatim(qemuMonitorTestPtr test,
625 qemuMonitorTestItemPtr item,
626 const char *cmdstr)
628 struct qemuMonitorTestHandlerData *data = item->opaque;
629 VIR_AUTOFREE(char *) reformatted = NULL;
630 VIR_AUTOFREE(char *) errmsg = NULL;
631 VIR_AUTOPTR(virJSONValue) json = NULL;
632 virJSONValuePtr cmdargs;
633 const char *cmdname;
634 int ret = -1;
635 int rc;
637 /* JSON strings will be reformatted to simplify checking */
638 if (!(json = virJSONValueFromString(cmdstr)) ||
639 !(reformatted = virJSONValueToString(json, false)))
640 return -1;
642 cmdstr = reformatted;
644 /* in this case we do a best-effort schema check if we can find the command */
645 if ((cmdname = virJSONValueObjectGetString(json, "execute"))) {
646 cmdargs = virJSONValueObjectGet(json, "arguments");
648 if ((rc = qemuMonitorTestProcessCommandDefaultValidate(test, cmdname, cmdargs)) < 0)
649 return -1;
651 if (rc == 1)
652 return 0;
655 if (STREQ(data->command_name, cmdstr)) {
656 ret = qemuMonitorTestAddResponse(test, data->response);
657 } else {
658 if (data->cmderr) {
659 if (virAsprintf(&errmsg, "%s: %s", data->cmderr, cmdstr) < 0)
660 return -1;
662 ret = qemuMonitorTestAddErrorResponse(test, errmsg);
663 } else {
664 ret = qemuMonitorTestAddInvalidCommandResponse(test,
665 data->command_name,
666 cmdstr);
670 return ret;
675 * qemuMonitorTestAddItemVerbatim:
676 * @test: monitor test object
677 * @command: full expected command syntax
678 * @cmderr: possible explanation of expected command (may be NULL)
679 * @response: full reply of @command
681 * Adds a test command for the simulated monitor. The full syntax is checked
682 * as specified in @command. For JSON monitor tests formatting/whitespace is
683 * ignored. If the command on the monitor is not as expected an error containing
684 * @cmderr is returned. Otherwise @response is put as-is on the monitor.
686 * Returns 0 when command was successfully added, -1 on error.
689 qemuMonitorTestAddItemVerbatim(qemuMonitorTestPtr test,
690 const char *command,
691 const char *cmderr,
692 const char *response)
694 struct qemuMonitorTestHandlerData *data;
696 if (VIR_ALLOC(data) < 0)
697 return -1;
699 if (VIR_STRDUP(data->response, response) < 0 ||
700 VIR_STRDUP(data->cmderr, cmderr) < 0)
701 goto error;
703 data->command_name = virJSONStringReformat(command, false);
704 if (!data->command_name)
705 goto error;
707 return qemuMonitorTestAddHandler(test,
708 qemuMonitorTestProcessCommandVerbatim,
709 data, qemuMonitorTestHandlerDataFree);
711 error:
712 qemuMonitorTestHandlerDataFree(data);
713 return -1;
717 static int
718 qemuMonitorTestProcessGuestAgentSync(qemuMonitorTestPtr test,
719 qemuMonitorTestItemPtr item ATTRIBUTE_UNUSED,
720 const char *cmdstr)
722 virJSONValuePtr val = NULL;
723 virJSONValuePtr args;
724 unsigned long long id;
725 const char *cmdname;
726 char *retmsg = NULL;
727 int ret = -1;
729 if (!(val = virJSONValueFromString(cmdstr)))
730 return -1;
732 if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) {
733 ret = qemuMonitorReportError(test, "Missing guest-sync command name");
734 goto cleanup;
737 if (STRNEQ(cmdname, "guest-sync")) {
738 ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-sync", cmdname);
739 goto cleanup;
742 if (!(args = virJSONValueObjectGet(val, "arguments"))) {
743 ret = qemuMonitorReportError(test, "Missing arguments for guest-sync");
744 goto cleanup;
747 if (virJSONValueObjectGetNumberUlong(args, "id", &id)) {
748 ret = qemuMonitorReportError(test, "Missing id for guest sync");
749 goto cleanup;
752 if (virAsprintf(&retmsg, "{\"return\":%llu}", id) < 0)
753 goto cleanup;
756 ret = qemuMonitorTestAddResponse(test, retmsg);
758 cleanup:
759 virJSONValueFree(val);
760 VIR_FREE(retmsg);
761 return ret;
766 qemuMonitorTestAddAgentSyncResponse(qemuMonitorTestPtr test)
768 if (!test->agent) {
769 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
770 "This test is not an agent test");
771 return -1;
774 return qemuMonitorTestAddHandler(test,
775 qemuMonitorTestProcessGuestAgentSync,
776 NULL, NULL);
780 static int
781 qemuMonitorTestProcessCommandWithArgs(qemuMonitorTestPtr test,
782 qemuMonitorTestItemPtr item,
783 const char *cmdstr)
785 struct qemuMonitorTestHandlerData *data = item->opaque;
786 virJSONValuePtr val = NULL;
787 virJSONValuePtr args;
788 virJSONValuePtr argobj;
789 char *argstr = NULL;
790 const char *cmdname;
791 size_t i;
792 int ret = -1;
794 if (!(val = virJSONValueFromString(cmdstr)))
795 return -1;
797 if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) {
798 ret = qemuMonitorReportError(test, "Missing command name in %s", cmdstr);
799 goto cleanup;
802 if (data->command_name &&
803 STRNEQ(data->command_name, cmdname)) {
804 ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name,
805 cmdname);
806 goto cleanup;
809 if (!(args = virJSONValueObjectGet(val, "arguments"))) {
810 ret = qemuMonitorReportError(test,
811 "Missing arguments section for command '%s'",
812 NULLSTR(data->command_name));
813 goto cleanup;
816 /* validate the args */
817 for (i = 0; i < data->nargs; i++) {
818 qemuMonitorTestCommandArgsPtr arg = &data->args[i];
819 if (!(argobj = virJSONValueObjectGet(args, arg->argname))) {
820 ret = qemuMonitorReportError(test,
821 "Missing argument '%s' for command '%s'",
822 arg->argname,
823 NULLSTR(data->command_name));
824 goto cleanup;
827 /* convert the argument to string */
828 if (!(argstr = virJSONValueToString(argobj, false)))
829 goto cleanup;
831 /* verify that the argument value is expected */
832 if (STRNEQ(argstr, arg->argval)) {
833 ret = qemuMonitorReportError(test,
834 "Invalid value of argument '%s' "
835 "of command '%s': "
836 "expected '%s' got '%s'",
837 arg->argname,
838 NULLSTR(data->command_name),
839 arg->argval, argstr);
840 goto cleanup;
843 VIR_FREE(argstr);
846 /* arguments checked out, return the response */
847 ret = qemuMonitorTestAddResponse(test, data->response);
849 cleanup:
850 VIR_FREE(argstr);
851 virJSONValueFree(val);
852 return ret;
857 /* this allows to add a responder that is able to check
858 * a (shallow) structure of arguments for a command */
860 qemuMonitorTestAddItemParams(qemuMonitorTestPtr test,
861 const char *cmdname,
862 const char *response,
863 ...)
865 struct qemuMonitorTestHandlerData *data;
866 const char *argname;
867 const char *argval;
868 va_list args;
870 va_start(args, response);
872 if (VIR_ALLOC(data) < 0)
873 goto error;
875 if (VIR_STRDUP(data->command_name, cmdname) < 0 ||
876 VIR_STRDUP(data->response, response) < 0)
877 goto error;
879 while ((argname = va_arg(args, char *))) {
880 size_t i;
881 if (!(argval = va_arg(args, char *))) {
882 virReportError(VIR_ERR_INTERNAL_ERROR,
883 "Missing argument value for argument '%s'",
884 argname);
885 goto error;
888 i = data->nargs;
889 if (VIR_EXPAND_N(data->args, data->nargs, 1))
890 goto error;
892 if (VIR_STRDUP(data->args[i].argname, argname) < 0 ||
893 VIR_STRDUP(data->args[i].argval, argval) < 0)
894 goto error;
897 va_end(args);
899 return qemuMonitorTestAddHandler(test,
900 qemuMonitorTestProcessCommandWithArgs,
901 data, qemuMonitorTestHandlerDataFree);
903 error:
904 va_end(args);
905 qemuMonitorTestHandlerDataFree(data);
906 return -1;
910 static int
911 qemuMonitorTestProcessCommandWithArgStr(qemuMonitorTestPtr test,
912 qemuMonitorTestItemPtr item,
913 const char *cmdstr)
915 struct qemuMonitorTestHandlerData *data = item->opaque;
916 virJSONValuePtr val = NULL;
917 virJSONValuePtr args;
918 char *argstr = NULL;
919 const char *cmdname;
920 int ret = -1;
922 if (!(val = virJSONValueFromString(cmdstr)))
923 return -1;
925 if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) {
926 ret = qemuMonitorReportError(test, "Missing command name in %s", cmdstr);
927 goto cleanup;
930 if (STRNEQ(data->command_name, cmdname)) {
931 ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name,
932 cmdname);
933 goto cleanup;
936 if (!(args = virJSONValueObjectGet(val, "arguments"))) {
937 ret = qemuMonitorReportError(test,
938 "Missing arguments section for command '%s'",
939 data->command_name);
940 goto cleanup;
943 /* convert the arguments to string */
944 if (!(argstr = virJSONValueToString(args, false)))
945 goto cleanup;
947 /* verify that the argument value is expected */
948 if (STRNEQ(argstr, data->expectArgs)) {
949 ret = qemuMonitorReportError(test,
950 "%s: expected arguments: '%s', got: '%s'",
951 data->command_name,
952 data->expectArgs, argstr);
953 goto cleanup;
956 /* arguments checked out, return the response */
957 ret = qemuMonitorTestAddResponse(test, data->response);
959 cleanup:
960 VIR_FREE(argstr);
961 virJSONValueFree(val);
962 return ret;
967 * qemuMonitorTestAddItemExpect:
969 * @test: test monitor object
970 * @cmdname: command name
971 * @cmdargs: expected arguments of the command
972 * @apostrophe: convert apostrophes (') in @cmdargs to quotes (")
973 * @response: simulated response of the command
975 * Simulates a qemu monitor command. Checks that the 'arguments' of the qmp
976 * command are expected. If @apostrophe is true apostrophes are converted to
977 * quotes for simplification of writing the strings into code.
980 qemuMonitorTestAddItemExpect(qemuMonitorTestPtr test,
981 const char *cmdname,
982 const char *cmdargs,
983 bool apostrophe,
984 const char *response)
986 struct qemuMonitorTestHandlerData *data;
988 if (VIR_ALLOC(data) < 0)
989 goto error;
991 if (VIR_STRDUP(data->command_name, cmdname) < 0 ||
992 VIR_STRDUP(data->response, response) < 0 ||
993 VIR_STRDUP(data->expectArgs, cmdargs) < 0)
994 goto error;
996 if (apostrophe) {
997 char *tmp = data->expectArgs;
999 while (*tmp != '\0') {
1000 if (*tmp == '\'')
1001 *tmp = '"';
1003 tmp++;
1007 return qemuMonitorTestAddHandler(test,
1008 qemuMonitorTestProcessCommandWithArgStr,
1009 data, qemuMonitorTestHandlerDataFree);
1011 error:
1012 qemuMonitorTestHandlerDataFree(data);
1013 return -1;
1017 static void
1018 qemuMonitorTestEOFNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
1019 virDomainObjPtr vm ATTRIBUTE_UNUSED,
1020 void *opaque ATTRIBUTE_UNUSED)
1025 static void
1026 qemuMonitorTestErrorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
1027 virDomainObjPtr vm ATTRIBUTE_UNUSED,
1028 void *opaque ATTRIBUTE_UNUSED)
1033 static qemuMonitorCallbacks qemuMonitorTestCallbacks = {
1034 .eofNotify = qemuMonitorTestEOFNotify,
1035 .errorNotify = qemuMonitorTestErrorNotify,
1036 .domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
1040 static void
1041 qemuMonitorTestAgentNotify(qemuAgentPtr agent ATTRIBUTE_UNUSED,
1042 virDomainObjPtr vm ATTRIBUTE_UNUSED)
1047 static qemuAgentCallbacks qemuMonitorTestAgentCallbacks = {
1048 .eofNotify = qemuMonitorTestAgentNotify,
1049 .errorNotify = qemuMonitorTestAgentNotify,
1053 static qemuMonitorTestPtr
1054 qemuMonitorCommonTestNew(virDomainXMLOptionPtr xmlopt,
1055 virDomainObjPtr vm,
1056 virDomainChrSourceDefPtr src)
1058 qemuMonitorTestPtr test = NULL;
1059 char *path = NULL;
1060 char *tmpdir_template = NULL;
1062 if (VIR_ALLOC(test) < 0)
1063 goto error;
1065 if (virMutexInit(&test->lock) < 0) {
1066 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1067 "Cannot initialize mutex");
1068 VIR_FREE(test);
1069 return NULL;
1072 if (VIR_STRDUP(tmpdir_template, "/tmp/libvirt_XXXXXX") < 0)
1073 goto error;
1075 if (!(test->tmpdir = mkdtemp(tmpdir_template))) {
1076 virReportSystemError(errno, "%s",
1077 "Failed to create temporary directory");
1078 goto error;
1081 tmpdir_template = NULL;
1083 if (virAsprintf(&path, "%s/qemumonitorjsontest.sock", test->tmpdir) < 0)
1084 goto error;
1086 if (vm) {
1087 test->vm = virObjectRef(vm);
1088 } else {
1089 test->vm = virDomainObjNew(xmlopt);
1090 if (!test->vm)
1091 goto error;
1094 if (virNetSocketNewListenUNIX(path, 0700, geteuid(), getegid(),
1095 &test->server) < 0)
1096 goto error;
1098 memset(src, 0, sizeof(*src));
1099 src->type = VIR_DOMAIN_CHR_TYPE_UNIX;
1100 src->data.nix.path = (char *)path;
1101 src->data.nix.listen = false;
1102 path = NULL;
1104 if (virNetSocketListen(test->server, 1) < 0)
1105 goto error;
1107 cleanup:
1108 return test;
1110 error:
1111 VIR_FREE(path);
1112 VIR_FREE(tmpdir_template);
1113 qemuMonitorTestFree(test);
1114 test = NULL;
1115 goto cleanup;
1120 static int
1121 qemuMonitorCommonTestInit(qemuMonitorTestPtr test)
1123 int events = VIR_EVENT_HANDLE_READABLE;
1125 if (!test)
1126 return -1;
1128 if (virNetSocketAccept(test->server, &test->client) < 0)
1129 goto error;
1131 if (!test->client)
1132 goto error;
1134 if (test->outgoingLength > 0)
1135 events = VIR_EVENT_HANDLE_WRITABLE;
1137 if (virNetSocketAddIOCallback(test->client,
1138 events,
1139 qemuMonitorTestIO,
1140 test,
1141 NULL) < 0)
1142 goto error;
1144 virMutexLock(&test->lock);
1145 if (virThreadCreate(&test->thread,
1146 true,
1147 qemuMonitorTestWorker,
1148 test) < 0) {
1149 virMutexUnlock(&test->lock);
1150 goto error;
1152 test->started = test->running = true;
1153 virMutexUnlock(&test->lock);
1155 return 0;
1157 error:
1158 return -1;
1162 #define QEMU_JSON_GREETING "{\"QMP\":"\
1163 " {\"version\":"\
1164 " {\"qemu\":"\
1165 " {\"micro\": 1,"\
1166 " \"minor\": 0,"\
1167 " \"major\": 1"\
1168 " },"\
1169 " \"package\": \"(qemu-kvm-1.0.1)"\
1170 " \"},"\
1171 " \"capabilities\": []"\
1172 " }"\
1174 /* We skip the normal handshake reply of "{\"execute\":\"qmp_capabilities\"}" */
1176 qemuMonitorTestPtr
1177 qemuMonitorTestNew(virDomainXMLOptionPtr xmlopt,
1178 virDomainObjPtr vm,
1179 virQEMUDriverPtr driver,
1180 const char *greeting,
1181 virHashTablePtr schema)
1183 qemuMonitorTestPtr test = NULL;
1184 virDomainChrSourceDef src;
1186 memset(&src, 0, sizeof(src));
1188 if (!(test = qemuMonitorCommonTestNew(xmlopt, vm, &src)))
1189 goto error;
1191 test->qapischema = schema;
1192 if (!(test->mon = qemuMonitorOpen(test->vm,
1193 &src,
1194 true,
1196 &qemuMonitorTestCallbacks,
1197 driver)))
1198 goto error;
1200 virObjectLock(test->mon);
1202 if (!greeting)
1203 greeting = QEMU_JSON_GREETING;
1205 if (qemuMonitorTestAddResponse(test, greeting) < 0)
1206 goto error;
1208 if (qemuMonitorCommonTestInit(test) < 0)
1209 goto error;
1211 virDomainChrSourceDefClear(&src);
1213 return test;
1215 error:
1216 virDomainChrSourceDefClear(&src);
1217 qemuMonitorTestFree(test);
1218 return NULL;
1223 * qemuMonitorTestNewFromFile:
1224 * @fileName: File name to load monitor replies from
1225 * @xmlopt: XML parser configuration object
1226 * @simple: see below
1228 * Create a JSON test monitor simulator object and fill it with replies
1229 * specified in @fileName. The file contains JSON reply objects separated by
1230 * empty lines. If @simple is true a generic QMP greeting is automatically
1231 * added as the first reply, otherwise the first entry in the file is used.
1233 * Returns the monitor object on success; NULL on error.
1235 qemuMonitorTestPtr
1236 qemuMonitorTestNewFromFile(const char *fileName,
1237 virDomainXMLOptionPtr xmlopt,
1238 bool simple)
1240 qemuMonitorTestPtr test = NULL;
1241 char *json = NULL;
1242 char *tmp;
1243 char *singleReply;
1245 if (virTestLoadFile(fileName, &json) < 0)
1246 goto cleanup;
1248 if (simple && !(test = qemuMonitorTestNewSimple(xmlopt)))
1249 goto cleanup;
1251 /* Our JSON parser expects replies to be separated by a newline character.
1252 * Hence we must preprocess the file a bit. */
1253 tmp = singleReply = json;
1254 while ((tmp = strchr(tmp, '\n'))) {
1255 /* It is safe to touch tmp[1] since all strings ends with '\0'. */
1256 bool eof = !tmp[1];
1258 if (*(tmp + 1) != '\n') {
1259 *tmp = ' ';
1260 tmp++;
1261 } else {
1262 /* Cut off a single reply. */
1263 *(tmp + 1) = '\0';
1265 if (test) {
1266 if (qemuMonitorTestAddItem(test, NULL, singleReply) < 0)
1267 goto error;
1268 } else {
1269 /* Create new mocked monitor with our greeting */
1270 if (!(test = qemuMonitorTestNew(xmlopt, NULL, NULL,
1271 singleReply, NULL)))
1272 goto error;
1275 if (!eof) {
1276 /* Move the @tmp and @singleReply. */
1277 tmp += 2;
1278 singleReply = tmp;
1282 if (eof)
1283 break;
1286 if (test && qemuMonitorTestAddItem(test, NULL, singleReply) < 0)
1287 goto error;
1289 cleanup:
1290 VIR_FREE(json);
1291 return test;
1293 error:
1294 qemuMonitorTestFree(test);
1295 test = NULL;
1296 goto cleanup;
1300 static int
1301 qemuMonitorTestFullAddItem(qemuMonitorTestPtr test,
1302 const char *filename,
1303 const char *command,
1304 const char *response,
1305 size_t line)
1307 char *cmderr;
1308 int ret;
1310 if (virAsprintf(&cmderr, "wrong expected command in %s:%zu: ",
1311 filename, line) < 0)
1312 return -1;
1314 ret = qemuMonitorTestAddItemVerbatim(test, command, cmderr, response);
1316 VIR_FREE(cmderr);
1317 return ret;
1322 * qemuMonitorTestNewFromFileFull:
1323 * @fileName: File name to load monitor replies from
1324 * @driver: qemu driver object
1325 * @vm: domain object (may be null if it's not needed by the test)
1326 * @qmpschema: QMP schema data hash table if QMP checking is required
1328 * Create a JSON test monitor simulator object and fill it with expected command
1329 * sequence and replies specified in @fileName.
1331 * The file contains a sequence of JSON commands and reply objects separated by
1332 * empty lines. A command is followed by a reply. The QMP greeting is added
1333 * automatically.
1335 * Returns the monitor object on success; NULL on error.
1337 qemuMonitorTestPtr
1338 qemuMonitorTestNewFromFileFull(const char *fileName,
1339 virQEMUDriverPtr driver,
1340 virDomainObjPtr vm,
1341 virHashTablePtr qmpschema)
1343 qemuMonitorTestPtr ret = NULL;
1344 char *jsonstr = NULL;
1345 char *tmp;
1346 size_t line = 0;
1348 char *command = NULL;
1349 char *response = NULL;
1350 size_t commandln = 0;
1352 if (virTestLoadFile(fileName, &jsonstr) < 0)
1353 return NULL;
1355 if (!(ret = qemuMonitorTestNew(driver->xmlopt, vm, driver, NULL,
1356 qmpschema)))
1357 goto cleanup;
1359 tmp = jsonstr;
1360 command = tmp;
1361 while ((tmp = strchr(tmp, '\n'))) {
1362 line++;
1364 /* eof */
1365 if (!tmp[1])
1366 break;
1368 /* concatenate block which was broken up for readability */
1369 if (*(tmp + 1) != '\n') {
1370 *tmp = ' ';
1371 tmp++;
1372 continue;
1375 /* Cut off a single reply. */
1376 *(tmp + 1) = '\0';
1378 if (response) {
1379 if (qemuMonitorTestFullAddItem(ret, fileName, command,
1380 response, commandln) < 0)
1381 goto error;
1382 command = NULL;
1383 response = NULL;
1386 /* Move the @tmp and @singleReply. */
1387 tmp += 2;
1389 if (!command) {
1390 commandln = line;
1391 command = tmp;
1392 } else {
1393 response = tmp;
1397 if (command) {
1398 if (!response) {
1399 virReportError(VIR_ERR_INTERNAL_ERROR, "missing response for command "
1400 "on line '%zu' in '%s'", commandln, fileName);
1401 goto error;
1404 if (qemuMonitorTestFullAddItem(ret, fileName, command,
1405 response, commandln) < 0)
1406 goto error;
1409 cleanup:
1410 VIR_FREE(jsonstr);
1411 return ret;
1413 error:
1414 qemuMonitorTestFree(ret);
1415 ret = NULL;
1416 goto cleanup;
1420 qemuMonitorTestPtr
1421 qemuMonitorTestNewAgent(virDomainXMLOptionPtr xmlopt)
1423 qemuMonitorTestPtr test = NULL;
1424 virDomainChrSourceDef src;
1426 memset(&src, 0, sizeof(src));
1428 if (!(test = qemuMonitorCommonTestNew(xmlopt, NULL, &src)))
1429 goto error;
1431 if (!(test->agent = qemuAgentOpen(test->vm,
1432 &src,
1433 &qemuMonitorTestAgentCallbacks)))
1434 goto error;
1436 virObjectLock(test->agent);
1438 if (qemuMonitorCommonTestInit(test) < 0)
1439 goto error;
1441 virDomainChrSourceDefClear(&src);
1443 return test;
1445 error:
1446 virDomainChrSourceDefClear(&src);
1447 qemuMonitorTestFree(test);
1448 return NULL;
1452 qemuMonitorPtr
1453 qemuMonitorTestGetMonitor(qemuMonitorTestPtr test)
1455 return test->mon;
1459 qemuAgentPtr
1460 qemuMonitorTestGetAgent(qemuMonitorTestPtr test)
1462 return test->agent;
1466 virDomainObjPtr
1467 qemuMonitorTestGetDomainObj(qemuMonitorTestPtr test)
1469 return test->vm;