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,
 | 
					void qpci_plug_device_test(const char *driver, const char *id,
 | 
				
			||||||
                           uint8_t slot, const char *opts)
 | 
					                           uint8_t slot, const char *opts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QDict *response;
 | 
					    qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
 | 
				
			||||||
    char *cmd;
 | 
					                         opts ? ", " : "", opts ? opts : "");
 | 
				
			||||||
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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 usb_test_hotplug(const char *hcd_id, const int port,
 | 
				
			||||||
                      void (*port_check)(void))
 | 
					                      void (*port_check)(void))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QDict *response;
 | 
					    char  *id = g_strdup_printf("usbdev%d", port);
 | 
				
			||||||
    char  *cmd;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cmd = g_strdup_printf("{'execute': 'device_add',"
 | 
					    qtest_qmp_device_add("usb-tablet", id, "'port': '%d', 'bus': '%s.0'",
 | 
				
			||||||
                          " 'arguments': {"
 | 
					                         port, hcd_id);
 | 
				
			||||||
                          "   '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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (port_check) {
 | 
					    if (port_check) {
 | 
				
			||||||
        port_check();
 | 
					        port_check();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cmd = g_strdup_printf("{'execute': 'device_del',"
 | 
					    qtest_qmp_device_del(id);
 | 
				
			||||||
                           " 'arguments': {"
 | 
					
 | 
				
			||||||
                           "   'id': 'usbdev%d'"
 | 
					    g_free(id);
 | 
				
			||||||
                           "}}", 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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -987,3 +987,78 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
 | 
				
			|||||||
    qtest_end();
 | 
					    qtest_end();
 | 
				
			||||||
    QDECREF(response);
 | 
					    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));
 | 
					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
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -48,31 +48,9 @@ static void test_uhci_hotplug(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void test_usb_storage_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',"
 | 
					    qtest_qmp_device_del("usbdev0");
 | 
				
			||||||
                   " '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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
				
			|||||||
@ -23,59 +23,16 @@ static void test_xhci_hotplug(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void test_usb_uas_hotplug(void)
 | 
					static void test_usb_uas_hotplug(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QDict *response;
 | 
					    qtest_qmp_device_add("usb-uas", "uas", NULL);
 | 
				
			||||||
 | 
					    qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drive0'");
 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* TODO:
 | 
					    /* TODO:
 | 
				
			||||||
        UAS HBA driver in libqos, to check that
 | 
					        UAS HBA driver in libqos, to check that
 | 
				
			||||||
        added disk is visible after BUS rescan
 | 
					        added disk is visible after BUS rescan
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    response = qmp("{'execute': 'device_del',"
 | 
					    qtest_qmp_device_del("scsihd");
 | 
				
			||||||
                           " 'arguments': {"
 | 
					    qtest_qmp_device_del("uas");
 | 
				
			||||||
                           "   '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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
				
			|||||||
@ -192,32 +192,12 @@ static void pci_nop(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void hotplug(void)
 | 
					static void hotplug(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QDict *response;
 | 
					 | 
				
			||||||
    QOSState *qs;
 | 
					    QOSState *qs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qs = qvirtio_scsi_start(
 | 
					    qs = qvirtio_scsi_start(
 | 
				
			||||||
            "-drive id=drv1,if=none,file=null-co://,format=raw");
 | 
					            "-drive id=drv1,if=none,file=null-co://,format=raw");
 | 
				
			||||||
    response = qmp("{\"execute\": \"device_add\","
 | 
					    qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drv1'");
 | 
				
			||||||
                   " \"arguments\": {"
 | 
					    qtest_qmp_device_del("scsihd");
 | 
				
			||||||
                   "   \"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);
 | 
					 | 
				
			||||||
    qvirtio_scsi_stop(qs);
 | 
					    qvirtio_scsi_stop(qs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,28 +17,9 @@ static void pci_nop(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void hotplug(void)
 | 
					static void hotplug(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QDict *response;
 | 
					    qtest_qmp_device_add("virtserialport", "hp-port", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    response = qmp("{\"execute\": \"device_add\","
 | 
					    qtest_qmp_device_del("hp-port");
 | 
				
			||||||
                   " \"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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user