mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
tests: Introduce generic device hot-plug/hot-unplug functions
A lot of tests provide code for adding and removing a device via the device_add and device_del QMP commands. Maintaining this code in so many places is cumbersome and error-prone (some of the code parts check the responses for device deletion in an incorrect way, for example, we've got to deal with both, error code and DEVICE_DEL event here). So let's provide some proper generic functions for adding and removing a device instead. The code for correctly unplugging a device has been taken from a patch from Peter Xu. Reviewed-by: Peter Xu <peterx@redhat.com> Tested-by: Peter Xu <peterx@redhat.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
3dabde1128
commit
acd80015fb
@ -394,21 +394,6 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
|
||||
void qpci_plug_device_test(const char *driver, const char *id,
|
||||
uint8_t slot, const char *opts)
|
||||
{
|
||||
QDict *response;
|
||||
char *cmd;
|
||||
|
||||
cmd = g_strdup_printf("{'execute': 'device_add',"
|
||||
" 'arguments': {"
|
||||
" 'driver': '%s',"
|
||||
" 'addr': '%d',"
|
||||
" %s%s"
|
||||
" 'id': '%s'"
|
||||
"}}", driver, slot,
|
||||
opts ? opts : "", opts ? "," : "",
|
||||
id);
|
||||
response = qmp(cmd);
|
||||
g_free(cmd);
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
|
||||
opts ? ", " : "", opts ? opts : "");
|
||||
}
|
||||
|
@ -40,34 +40,16 @@ void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
|
||||
void usb_test_hotplug(const char *hcd_id, const int port,
|
||||
void (*port_check)(void))
|
||||
{
|
||||
QDict *response;
|
||||
char *cmd;
|
||||
char *id = g_strdup_printf("usbdev%d", port);
|
||||
|
||||
cmd = g_strdup_printf("{'execute': 'device_add',"
|
||||
" 'arguments': {"
|
||||
" 'driver': 'usb-tablet',"
|
||||
" 'port': '%d',"
|
||||
" 'bus': '%s.0',"
|
||||
" 'id': 'usbdev%d'"
|
||||
"}}", port, hcd_id, port);
|
||||
response = qmp(cmd);
|
||||
g_free(cmd);
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_add("usb-tablet", id, "'port': '%d', 'bus': '%s.0'",
|
||||
port, hcd_id);
|
||||
|
||||
if (port_check) {
|
||||
port_check();
|
||||
}
|
||||
|
||||
cmd = g_strdup_printf("{'execute': 'device_del',"
|
||||
" 'arguments': {"
|
||||
" 'id': 'usbdev%d'"
|
||||
"}}", port);
|
||||
response = qmp(cmd);
|
||||
g_free(cmd);
|
||||
g_assert(response);
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_del(id);
|
||||
|
||||
g_free(id);
|
||||
}
|
||||
|
@ -987,3 +987,78 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
|
||||
qtest_end();
|
||||
QDECREF(response);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic hot-plugging test via the device_add QMP command.
|
||||
*/
|
||||
void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
|
||||
...)
|
||||
{
|
||||
QDict *response;
|
||||
char *cmd, *opts = NULL;
|
||||
va_list va;
|
||||
|
||||
if (fmt) {
|
||||
va_start(va, fmt);
|
||||
opts = g_strdup_vprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
cmd = g_strdup_printf("{'execute': 'device_add',"
|
||||
" 'arguments': { 'driver': '%s', 'id': '%s'%s%s }}",
|
||||
driver, id, opts ? ", " : "", opts ? opts : "");
|
||||
g_free(opts);
|
||||
|
||||
response = qmp(cmd);
|
||||
g_free(cmd);
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "event")); /* We don't expect any events */
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic hot-unplugging test via the device_del QMP command.
|
||||
* Device deletion will get one response and one event. For example:
|
||||
*
|
||||
* {'execute': 'device_del','arguments': { 'id': 'scsi-hd'}}
|
||||
*
|
||||
* will get this one:
|
||||
*
|
||||
* {"timestamp": {"seconds": 1505289667, "microseconds": 569862},
|
||||
* "event": "DEVICE_DELETED", "data": {"device": "scsi-hd",
|
||||
* "path": "/machine/peripheral/scsi-hd"}}
|
||||
*
|
||||
* and this one:
|
||||
*
|
||||
* {"return": {}}
|
||||
*
|
||||
* But the order of arrival may vary - so we've got to detect both.
|
||||
*/
|
||||
void qtest_qmp_device_del(const char *id)
|
||||
{
|
||||
QDict *response1, *response2, *event = NULL;
|
||||
char *cmd;
|
||||
|
||||
cmd = g_strdup_printf("{'execute': 'device_del',"
|
||||
" 'arguments': { 'id': '%s' }}", id);
|
||||
response1 = qmp(cmd);
|
||||
g_free(cmd);
|
||||
g_assert(response1);
|
||||
g_assert(!qdict_haskey(response1, "error"));
|
||||
|
||||
response2 = qmp("");
|
||||
g_assert(response2);
|
||||
g_assert(!qdict_haskey(response2, "error"));
|
||||
|
||||
if (qdict_haskey(response1, "event")) {
|
||||
event = response1;
|
||||
} else if (qdict_haskey(response2, "event")) {
|
||||
event = response2;
|
||||
}
|
||||
g_assert(event);
|
||||
g_assert_cmpstr(qdict_get_str(event, "event"), ==, "DEVICE_DELETED");
|
||||
|
||||
QDECREF(response1);
|
||||
QDECREF(response2);
|
||||
}
|
||||
|
@ -927,4 +927,23 @@ QDict *qmp_fd(int fd, const char *fmt, ...);
|
||||
*/
|
||||
void qtest_cb_for_every_machine(void (*cb)(const char *machine));
|
||||
|
||||
/**
|
||||
* qtest_qmp_device_add:
|
||||
* @driver: Name of the device that should be added
|
||||
* @id: Identification string
|
||||
* @fmt: printf-like format string for further options to device_add
|
||||
*
|
||||
* Generic hot-plugging test via the device_add QMP command.
|
||||
*/
|
||||
void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
|
||||
...) GCC_FMT_ATTR(3, 4);
|
||||
|
||||
/**
|
||||
* qtest_qmp_device_del:
|
||||
* @id: Identification string
|
||||
*
|
||||
* Generic hot-unplugging test via the device_del QMP command.
|
||||
*/
|
||||
void qtest_qmp_device_del(const char *id);
|
||||
|
||||
#endif
|
||||
|
@ -48,31 +48,9 @@ static void test_uhci_hotplug(void)
|
||||
|
||||
static void test_usb_storage_hotplug(void)
|
||||
{
|
||||
QDict *response;
|
||||
qtest_qmp_device_add("usb-storage", "usbdev0", "'drive': 'drive0'");
|
||||
|
||||
response = qmp("{'execute': 'device_add',"
|
||||
" 'arguments': {"
|
||||
" 'driver': 'usb-storage',"
|
||||
" 'drive': 'drive0',"
|
||||
" 'id': 'usbdev0'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("{'execute': 'device_del',"
|
||||
" 'arguments': {"
|
||||
" 'id': 'usbdev0'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("");
|
||||
g_assert(response);
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_del("usbdev0");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -23,59 +23,16 @@ static void test_xhci_hotplug(void)
|
||||
|
||||
static void test_usb_uas_hotplug(void)
|
||||
{
|
||||
QDict *response;
|
||||
|
||||
response = qmp("{'execute': 'device_add',"
|
||||
" 'arguments': {"
|
||||
" 'driver': 'usb-uas',"
|
||||
" 'id': 'uas'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("{'execute': 'device_add',"
|
||||
" 'arguments': {"
|
||||
" 'driver': 'scsi-hd',"
|
||||
" 'drive': 'drive0',"
|
||||
" 'id': 'scsi-hd'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_add("usb-uas", "uas", NULL);
|
||||
qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drive0'");
|
||||
|
||||
/* TODO:
|
||||
UAS HBA driver in libqos, to check that
|
||||
added disk is visible after BUS rescan
|
||||
*/
|
||||
|
||||
response = qmp("{'execute': 'device_del',"
|
||||
" 'arguments': {"
|
||||
" 'id': 'scsi-hd'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("");
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
|
||||
QDECREF(response);
|
||||
|
||||
|
||||
response = qmp("{'execute': 'device_del',"
|
||||
" 'arguments': {"
|
||||
" 'id': 'uas'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("");
|
||||
g_assert(response);
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_del("scsihd");
|
||||
qtest_qmp_device_del("uas");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -192,32 +192,12 @@ static void pci_nop(void)
|
||||
|
||||
static void hotplug(void)
|
||||
{
|
||||
QDict *response;
|
||||
QOSState *qs;
|
||||
|
||||
qs = qvirtio_scsi_start(
|
||||
"-drive id=drv1,if=none,file=null-co://,format=raw");
|
||||
response = qmp("{\"execute\": \"device_add\","
|
||||
" \"arguments\": {"
|
||||
" \"driver\": \"scsi-hd\","
|
||||
" \"id\": \"scsi-hd\","
|
||||
" \"drive\": \"drv1\""
|
||||
"}}");
|
||||
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("{\"execute\": \"device_del\","
|
||||
" \"arguments\": {"
|
||||
" \"id\": \"scsi-hd\""
|
||||
"}}");
|
||||
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drv1'");
|
||||
qtest_qmp_device_del("scsihd");
|
||||
qvirtio_scsi_stop(qs);
|
||||
}
|
||||
|
||||
|
@ -17,28 +17,9 @@ static void pci_nop(void)
|
||||
|
||||
static void hotplug(void)
|
||||
{
|
||||
QDict *response;
|
||||
qtest_qmp_device_add("virtserialport", "hp-port", NULL);
|
||||
|
||||
response = qmp("{\"execute\": \"device_add\","
|
||||
" \"arguments\": {"
|
||||
" \"driver\": \"virtserialport\","
|
||||
" \"id\": \"hp-port\""
|
||||
"}}");
|
||||
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
QDECREF(response);
|
||||
|
||||
response = qmp("{\"execute\": \"device_del\","
|
||||
" \"arguments\": {"
|
||||
" \"id\": \"hp-port\""
|
||||
"}}");
|
||||
|
||||
g_assert(response);
|
||||
g_assert(!qdict_haskey(response, "error"));
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
|
||||
QDECREF(response);
|
||||
qtest_qmp_device_del("hp-port");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
Loading…
Reference in New Issue
Block a user