tests/qtest/libqos/virtio-serial.c | 51 +++++++++ tests/qtest/libqos/virtio-serial.h | 2 + tests/qtest/virtio-serial-test.c | 177 ++++++++++++++++++++++++++++- 3 files changed, 228 insertions(+), 2 deletions(-)
The previous test cases for virtio-serial only tested initialization of
the device. I've included four new test cases: rx for virtconsole, tx
for virtconsole, rx for virtserialport, tx for virtserialport. It
follows the general pattern of virtio-net (i.e. chardev file descriptor
backend with a socketpair connected via fork-exec).
Signed-off-by: Daniel Hoffman <dhoff749@gmail.com>
---
tests/qtest/libqos/virtio-serial.c | 51 +++++++++
tests/qtest/libqos/virtio-serial.h | 2 +
tests/qtest/virtio-serial-test.c | 177 ++++++++++++++++++++++++++++-
3 files changed, 228 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/libqos/virtio-serial.c b/tests/qtest/libqos/virtio-serial.c
index 1d689c3e38..8723bffe1b 100644
--- a/tests/qtest/libqos/virtio-serial.c
+++ b/tests/qtest/libqos/virtio-serial.c
@@ -22,6 +22,10 @@
#include "qgraph.h"
#include "virtio-serial.h"
+#include "qemu/iov.h"
+
+static QGuestAllocator *alloc;
+
static void *qvirtio_serial_get_driver(QVirtioSerial *v_serial,
const char *interface)
{
@@ -43,6 +47,33 @@ static void *qvirtio_serial_device_get_driver(void *object,
return qvirtio_serial_get_driver(&v_serial->serial, interface);
}
+static void virtio_serial_setup(QVirtioSerial *interface)
+{
+ QVirtioDevice *vdev = interface->vdev;
+ qvirtio_set_features(vdev, (1ULL << 1) | (1ULL << 32));
+
+ interface->n_queues = 6;
+ interface->queues = g_new(QVirtQueue*, interface->n_queues);
+
+ for (int i = 0; i < interface->n_queues; i++) {
+ interface->queues[i] = qvirtqueue_setup(interface->vdev, alloc, i);
+ }
+
+ qvirtio_set_driver_ok(vdev);
+}
+
+static void qvirtio_serial_device_destructor(QOSGraphObject *obj)
+{
+}
+
+static void qvirtio_serial_device_start_hw(QOSGraphObject *obj)
+{
+ QVirtioSerialDevice *v_serial = (QVirtioSerialDevice *)obj;
+ QVirtioSerial *interface = &v_serial->serial;
+
+ virtio_serial_setup(interface);
+}
+
static void *virtio_serial_device_create(void *virtio_dev,
QGuestAllocator *t_alloc,
void *addr)
@@ -51,13 +82,30 @@ static void *virtio_serial_device_create(void *virtio_dev,
QVirtioSerial *interface = &virtio_device->serial;
interface->vdev = virtio_dev;
+ alloc = t_alloc;
+ virtio_device->obj.destructor = qvirtio_serial_device_destructor;
+ virtio_device->obj.start_hw = qvirtio_serial_device_start_hw;
virtio_device->obj.get_driver = qvirtio_serial_device_get_driver;
return &virtio_device->obj;
}
/* virtio-serial-pci */
+static void qvirtio_serial_pci_destructor(QOSGraphObject *obj)
+{
+}
+
+static void qvirtio_serial_pci_start_hw(QOSGraphObject *obj)
+{
+ QVirtioSerialPCI *v_serial = (QVirtioSerialPCI *) obj;
+ QVirtioSerial *interface = &v_serial->serial;
+ QOSGraphObject *pci_vobj = &v_serial->pci_vdev.obj;
+
+ qvirtio_pci_start_hw(pci_vobj);
+ virtio_serial_setup(interface);
+}
+
static void *qvirtio_serial_pci_get_driver(void *object, const char *interface)
{
QVirtioSerialPCI *v_serial = object;
@@ -76,7 +124,10 @@ static void *virtio_serial_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr);
interface->vdev = &virtio_spci->pci_vdev.vdev;
+ alloc = t_alloc;
+ obj->destructor = qvirtio_serial_pci_destructor;
+ obj->start_hw = qvirtio_serial_pci_start_hw;
obj->get_driver = qvirtio_serial_pci_get_driver;
return obj;
diff --git a/tests/qtest/libqos/virtio-serial.h b/tests/qtest/libqos/virtio-serial.h
index 3db43b2bb8..ce6ae164cb 100644
--- a/tests/qtest/libqos/virtio-serial.h
+++ b/tests/qtest/libqos/virtio-serial.h
@@ -29,6 +29,8 @@ typedef struct QVirtioSerialDevice QVirtioSerialDevice;
struct QVirtioSerial {
QVirtioDevice *vdev;
+ int n_queues;
+ QVirtQueue **queues;
};
struct QVirtioSerialPCI {
diff --git a/tests/qtest/virtio-serial-test.c b/tests/qtest/virtio-serial-test.c
index 2541034822..190075d6f5 100644
--- a/tests/qtest/virtio-serial-test.c
+++ b/tests/qtest/virtio-serial-test.c
@@ -11,6 +11,36 @@
#include "libqtest-single.h"
#include "qemu/module.h"
#include "libqos/virtio-serial.h"
+#include "standard-headers/linux/virtio_console.h"
+#include "qemu/iov.h"
+
+static void virtio_serial_test_cleanup(void *sockets)
+{
+ int *sv = sockets;
+
+ close(sv[0]);
+ qos_invalidate_command_line();
+ close(sv[1]);
+ g_free(sv);
+}
+
+static void *virtio_serial_test_setup(GString *cmd_line, void *arg)
+{
+ int ret;
+ int *sv = g_new(int, 3);
+
+ ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
+ g_assert_cmpint(ret, !=, -1);
+
+ g_string_append_printf(
+ cmd_line,
+ " -chardev socket,fd=%d,id=virtioserial0",
+ sv[1]);
+
+ sv[2] = arg ? 1 : 0;
+ g_test_queue_destroy(virtio_serial_test_cleanup, sv);
+ return sv;
+}
/* Tests only initialization so far. TODO: Replace with functional tests */
static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc)
@@ -18,6 +48,132 @@ static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc)
/* no operation */
}
+static void tx_test(
+ QVirtioDevice *dev,
+ QGuestAllocator *alloc,
+ QVirtQueue *vq,
+ int socket)
+{
+ QTestState *qts = global_qtest;
+ uint64_t req_addr;
+ uint64_t free_head;
+ char test[] = "TEST";
+ char buffer[5];
+ struct iovec iov[] = {
+ {
+ .iov_base = buffer,
+ .iov_len = strlen(test)
+ }
+ };
+ int ret;
+
+ req_addr = guest_alloc(alloc, 4);
+ qtest_memwrite(qts, req_addr, test, strlen(test));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 4, false, false);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ ret = iov_recv(socket, iov, 1, 0, strlen(test));
+ g_assert_cmpint(ret, ==, strlen(test));
+
+ buffer[strlen(test)] = '\0';
+ g_assert_cmpstr(buffer, ==, test);
+
+ guest_free(alloc, req_addr);
+}
+
+static void rx_test(
+ QVirtioDevice *dev,
+ QGuestAllocator *alloc,
+ QVirtQueue *vq,
+ int socket)
+{
+ QTestState *qts = global_qtest;
+ uint64_t req_addr;
+ uint64_t free_head;
+ char test[] = "TEST";
+ char buffer[5];
+ struct iovec iov[] = {
+ {
+ .iov_base = test,
+ .iov_len = strlen(test)
+ }
+ };
+ int ret;
+
+ req_addr = guest_alloc(alloc, 4);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 4, true, false);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ ret = iov_send(socket, iov, 1, 0, strlen(test));
+ g_assert_cmpint(ret, ==, strlen(test));
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, 5 * 1000 * 1000);
+ qtest_memread(qts, req_addr, buffer, strlen(test));
+
+ buffer[strlen(test)] = '\0';
+ g_assert_cmpstr(buffer, ==, test);
+
+ guest_free(alloc, req_addr);
+}
+
+static void send_recv_test(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QVirtioSerial *serial_if = obj;
+ QVirtioDevice *dev = serial_if->vdev;
+ uint32_t port_open_addr, port_open_free_head;
+ int *sv = data;
+
+ /*
+ * the first port is always virtconsole due to backwards compatibility
+ * consideraitons so we must use the multiport feature to add the correct
+ * port
+ */
+ QVirtQueue *rx = serial_if->queues[sv[2] == 0 ? 0 : 4];
+ QVirtQueue *tx = serial_if->queues[sv[2] == 0 ? 1 : 5];
+ QVirtQueue *control_tx = serial_if->queues[3];
+
+ port_open_addr = guest_alloc(alloc, 8);
+
+ qtest_writel(global_qtest, port_open_addr + 0, sv[2]);
+ qtest_writew(global_qtest, port_open_addr + 4, VIRTIO_CONSOLE_PORT_READY);
+ qtest_writew(global_qtest, port_open_addr + 6, 1);
+ port_open_free_head = qvirtqueue_add(
+ global_qtest,
+ control_tx,
+ port_open_addr,
+ 8,
+ false,
+ false);
+ qvirtqueue_kick(
+ global_qtest,
+ dev,
+ control_tx,
+ port_open_free_head);
+
+ qtest_writel(global_qtest, port_open_addr + 0, sv[2]);
+ qtest_writew(global_qtest, port_open_addr + 4, VIRTIO_CONSOLE_PORT_OPEN);
+ qtest_writew(global_qtest, port_open_addr + 6, 1);
+ port_open_free_head = qvirtqueue_add(
+ global_qtest,
+ control_tx,
+ port_open_addr,
+ 8,
+ false,
+ false);
+ qvirtqueue_kick(
+ global_qtest,
+ dev,
+ control_tx,
+ port_open_free_head);
+
+ guest_free(alloc, port_open_addr);
+
+ tx_test(dev, alloc, tx, sv[0]);
+ rx_test(dev, alloc, rx, sv[0]);
+}
+
static void serial_hotplug(void *obj, void *data, QGuestAllocator *alloc)
{
qtest_qmp_device_add(global_qtest, "virtserialport", "hp-port", "{}");
@@ -28,12 +184,29 @@ static void register_virtio_serial_test(void)
{
QOSGraphTestOptions opts = { };
- opts.edge.before_cmd_line = "-device virtconsole,bus=vser0.0";
+ opts.before = virtio_serial_test_setup;
+
+ opts.arg = (gpointer)0;
+ opts.edge.before_cmd_line =
+ "-device virtconsole,bus=vser0.0,chardev=virtioserial0";
qos_add_test("console-nop", "virtio-serial", virtio_serial_nop, &opts);
+ qos_add_test(
+ "console-send-recv",
+ "virtio-serial",
+ send_recv_test,
+ &opts);
- opts.edge.before_cmd_line = "-device virtserialport,bus=vser0.0";
+ opts.arg = (gpointer)1;
+ opts.edge.before_cmd_line =
+ "-device virtserialport,bus=vser0.0,chardev=virtioserial0";
qos_add_test("serialport-nop", "virtio-serial", virtio_serial_nop, &opts);
+ qos_add_test(
+ "serialport-send-recv",
+ "virtio-serial",
+ send_recv_test,
+ &opts);
+
qos_add_test("hotplug", "virtio-serial", serial_hotplug, NULL);
}
libqos_init(register_virtio_serial_test);
--
2.34.1
Is there interest in this? On Fri, Nov 11, 2022 at 10:33 PM Daniel Hoffman <dhoff749@gmail.com> wrote: > > The previous test cases for virtio-serial only tested initialization of > the device. I've included four new test cases: rx for virtconsole, tx > for virtconsole, rx for virtserialport, tx for virtserialport. It > follows the general pattern of virtio-net (i.e. chardev file descriptor > backend with a socketpair connected via fork-exec). > > Signed-off-by: Daniel Hoffman <dhoff749@gmail.com> > --- > tests/qtest/libqos/virtio-serial.c | 51 +++++++++ > tests/qtest/libqos/virtio-serial.h | 2 + > tests/qtest/virtio-serial-test.c | 177 ++++++++++++++++++++++++++++- > 3 files changed, 228 insertions(+), 2 deletions(-) > > diff --git a/tests/qtest/libqos/virtio-serial.c b/tests/qtest/libqos/virtio-serial.c > index 1d689c3e38..8723bffe1b 100644 > --- a/tests/qtest/libqos/virtio-serial.c > +++ b/tests/qtest/libqos/virtio-serial.c > @@ -22,6 +22,10 @@ > #include "qgraph.h" > #include "virtio-serial.h" > > +#include "qemu/iov.h" > + > +static QGuestAllocator *alloc; > + > static void *qvirtio_serial_get_driver(QVirtioSerial *v_serial, > const char *interface) > { > @@ -43,6 +47,33 @@ static void *qvirtio_serial_device_get_driver(void *object, > return qvirtio_serial_get_driver(&v_serial->serial, interface); > } > > +static void virtio_serial_setup(QVirtioSerial *interface) > +{ > + QVirtioDevice *vdev = interface->vdev; > + qvirtio_set_features(vdev, (1ULL << 1) | (1ULL << 32)); > + > + interface->n_queues = 6; > + interface->queues = g_new(QVirtQueue*, interface->n_queues); > + > + for (int i = 0; i < interface->n_queues; i++) { > + interface->queues[i] = qvirtqueue_setup(interface->vdev, alloc, i); > + } > + > + qvirtio_set_driver_ok(vdev); > +} > + > +static void qvirtio_serial_device_destructor(QOSGraphObject *obj) > +{ > +} > + > +static void qvirtio_serial_device_start_hw(QOSGraphObject *obj) > +{ > + QVirtioSerialDevice *v_serial = (QVirtioSerialDevice *)obj; > + QVirtioSerial *interface = &v_serial->serial; > + > + virtio_serial_setup(interface); > +} > + > static void *virtio_serial_device_create(void *virtio_dev, > QGuestAllocator *t_alloc, > void *addr) > @@ -51,13 +82,30 @@ static void *virtio_serial_device_create(void *virtio_dev, > QVirtioSerial *interface = &virtio_device->serial; > > interface->vdev = virtio_dev; > + alloc = t_alloc; > > + virtio_device->obj.destructor = qvirtio_serial_device_destructor; > + virtio_device->obj.start_hw = qvirtio_serial_device_start_hw; > virtio_device->obj.get_driver = qvirtio_serial_device_get_driver; > > return &virtio_device->obj; > } > > /* virtio-serial-pci */ > +static void qvirtio_serial_pci_destructor(QOSGraphObject *obj) > +{ > +} > + > +static void qvirtio_serial_pci_start_hw(QOSGraphObject *obj) > +{ > + QVirtioSerialPCI *v_serial = (QVirtioSerialPCI *) obj; > + QVirtioSerial *interface = &v_serial->serial; > + QOSGraphObject *pci_vobj = &v_serial->pci_vdev.obj; > + > + qvirtio_pci_start_hw(pci_vobj); > + virtio_serial_setup(interface); > +} > + > static void *qvirtio_serial_pci_get_driver(void *object, const char *interface) > { > QVirtioSerialPCI *v_serial = object; > @@ -76,7 +124,10 @@ static void *virtio_serial_pci_create(void *pci_bus, QGuestAllocator *t_alloc, > > virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr); > interface->vdev = &virtio_spci->pci_vdev.vdev; > + alloc = t_alloc; > > + obj->destructor = qvirtio_serial_pci_destructor; > + obj->start_hw = qvirtio_serial_pci_start_hw; > obj->get_driver = qvirtio_serial_pci_get_driver; > > return obj; > diff --git a/tests/qtest/libqos/virtio-serial.h b/tests/qtest/libqos/virtio-serial.h > index 3db43b2bb8..ce6ae164cb 100644 > --- a/tests/qtest/libqos/virtio-serial.h > +++ b/tests/qtest/libqos/virtio-serial.h > @@ -29,6 +29,8 @@ typedef struct QVirtioSerialDevice QVirtioSerialDevice; > > struct QVirtioSerial { > QVirtioDevice *vdev; > + int n_queues; > + QVirtQueue **queues; > }; > > struct QVirtioSerialPCI { > diff --git a/tests/qtest/virtio-serial-test.c b/tests/qtest/virtio-serial-test.c > index 2541034822..190075d6f5 100644 > --- a/tests/qtest/virtio-serial-test.c > +++ b/tests/qtest/virtio-serial-test.c > @@ -11,6 +11,36 @@ > #include "libqtest-single.h" > #include "qemu/module.h" > #include "libqos/virtio-serial.h" > +#include "standard-headers/linux/virtio_console.h" > +#include "qemu/iov.h" > + > +static void virtio_serial_test_cleanup(void *sockets) > +{ > + int *sv = sockets; > + > + close(sv[0]); > + qos_invalidate_command_line(); > + close(sv[1]); > + g_free(sv); > +} > + > +static void *virtio_serial_test_setup(GString *cmd_line, void *arg) > +{ > + int ret; > + int *sv = g_new(int, 3); > + > + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); > + g_assert_cmpint(ret, !=, -1); > + > + g_string_append_printf( > + cmd_line, > + " -chardev socket,fd=%d,id=virtioserial0", > + sv[1]); > + > + sv[2] = arg ? 1 : 0; > + g_test_queue_destroy(virtio_serial_test_cleanup, sv); > + return sv; > +} > > /* Tests only initialization so far. TODO: Replace with functional tests */ > static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc) > @@ -18,6 +48,132 @@ static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc) > /* no operation */ > } > > +static void tx_test( > + QVirtioDevice *dev, > + QGuestAllocator *alloc, > + QVirtQueue *vq, > + int socket) > +{ > + QTestState *qts = global_qtest; > + uint64_t req_addr; > + uint64_t free_head; > + char test[] = "TEST"; > + char buffer[5]; > + struct iovec iov[] = { > + { > + .iov_base = buffer, > + .iov_len = strlen(test) > + } > + }; > + int ret; > + > + req_addr = guest_alloc(alloc, 4); > + qtest_memwrite(qts, req_addr, test, strlen(test)); > + > + free_head = qvirtqueue_add(qts, vq, req_addr, 4, false, false); > + qvirtqueue_kick(qts, dev, vq, free_head); > + > + ret = iov_recv(socket, iov, 1, 0, strlen(test)); > + g_assert_cmpint(ret, ==, strlen(test)); > + > + buffer[strlen(test)] = '\0'; > + g_assert_cmpstr(buffer, ==, test); > + > + guest_free(alloc, req_addr); > +} > + > +static void rx_test( > + QVirtioDevice *dev, > + QGuestAllocator *alloc, > + QVirtQueue *vq, > + int socket) > +{ > + QTestState *qts = global_qtest; > + uint64_t req_addr; > + uint64_t free_head; > + char test[] = "TEST"; > + char buffer[5]; > + struct iovec iov[] = { > + { > + .iov_base = test, > + .iov_len = strlen(test) > + } > + }; > + int ret; > + > + req_addr = guest_alloc(alloc, 4); > + > + free_head = qvirtqueue_add(qts, vq, req_addr, 4, true, false); > + qvirtqueue_kick(qts, dev, vq, free_head); > + > + ret = iov_send(socket, iov, 1, 0, strlen(test)); > + g_assert_cmpint(ret, ==, strlen(test)); > + > + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, 5 * 1000 * 1000); > + qtest_memread(qts, req_addr, buffer, strlen(test)); > + > + buffer[strlen(test)] = '\0'; > + g_assert_cmpstr(buffer, ==, test); > + > + guest_free(alloc, req_addr); > +} > + > +static void send_recv_test(void *obj, void *data, QGuestAllocator *alloc) > +{ > + QVirtioSerial *serial_if = obj; > + QVirtioDevice *dev = serial_if->vdev; > + uint32_t port_open_addr, port_open_free_head; > + int *sv = data; > + > + /* > + * the first port is always virtconsole due to backwards compatibility > + * consideraitons so we must use the multiport feature to add the correct > + * port > + */ > + QVirtQueue *rx = serial_if->queues[sv[2] == 0 ? 0 : 4]; > + QVirtQueue *tx = serial_if->queues[sv[2] == 0 ? 1 : 5]; > + QVirtQueue *control_tx = serial_if->queues[3]; > + > + port_open_addr = guest_alloc(alloc, 8); > + > + qtest_writel(global_qtest, port_open_addr + 0, sv[2]); > + qtest_writew(global_qtest, port_open_addr + 4, VIRTIO_CONSOLE_PORT_READY); > + qtest_writew(global_qtest, port_open_addr + 6, 1); > + port_open_free_head = qvirtqueue_add( > + global_qtest, > + control_tx, > + port_open_addr, > + 8, > + false, > + false); > + qvirtqueue_kick( > + global_qtest, > + dev, > + control_tx, > + port_open_free_head); > + > + qtest_writel(global_qtest, port_open_addr + 0, sv[2]); > + qtest_writew(global_qtest, port_open_addr + 4, VIRTIO_CONSOLE_PORT_OPEN); > + qtest_writew(global_qtest, port_open_addr + 6, 1); > + port_open_free_head = qvirtqueue_add( > + global_qtest, > + control_tx, > + port_open_addr, > + 8, > + false, > + false); > + qvirtqueue_kick( > + global_qtest, > + dev, > + control_tx, > + port_open_free_head); > + > + guest_free(alloc, port_open_addr); > + > + tx_test(dev, alloc, tx, sv[0]); > + rx_test(dev, alloc, rx, sv[0]); > +} > + > static void serial_hotplug(void *obj, void *data, QGuestAllocator *alloc) > { > qtest_qmp_device_add(global_qtest, "virtserialport", "hp-port", "{}"); > @@ -28,12 +184,29 @@ static void register_virtio_serial_test(void) > { > QOSGraphTestOptions opts = { }; > > - opts.edge.before_cmd_line = "-device virtconsole,bus=vser0.0"; > + opts.before = virtio_serial_test_setup; > + > + opts.arg = (gpointer)0; > + opts.edge.before_cmd_line = > + "-device virtconsole,bus=vser0.0,chardev=virtioserial0"; > qos_add_test("console-nop", "virtio-serial", virtio_serial_nop, &opts); > + qos_add_test( > + "console-send-recv", > + "virtio-serial", > + send_recv_test, > + &opts); > > - opts.edge.before_cmd_line = "-device virtserialport,bus=vser0.0"; > + opts.arg = (gpointer)1; > + opts.edge.before_cmd_line = > + "-device virtserialport,bus=vser0.0,chardev=virtioserial0"; > qos_add_test("serialport-nop", "virtio-serial", virtio_serial_nop, &opts); > > + qos_add_test( > + "serialport-send-recv", > + "virtio-serial", > + send_recv_test, > + &opts); > + > qos_add_test("hotplug", "virtio-serial", serial_hotplug, NULL); > } > libqos_init(register_virtio_serial_test); > -- > 2.34.1 >
© 2016 - 2024 Red Hat, Inc.