[PATCH spice-gtk v4 26/29] test-cd-emu: Test attach/detach emulated device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Mock some usb-backend functions to be able to simulate device
attachment and detachment.
Create session and channel to pass some valid pointer anyway.
Emulate channel state correctly.
Make sure HELLO packets are sent correctly at the beginning and
no more afterwards.
Test auto-connect enabled or disabled.

Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx>
---
 tests/cd-emu.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 151 insertions(+), 2 deletions(-)

diff --git a/tests/cd-emu.c b/tests/cd-emu.c
index 7bf1fa3c..f0966662 100644
--- a/tests/cd-emu.c
+++ b/tests/cd-emu.c
@@ -14,10 +14,13 @@
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
-#include <gio/gio.h>
+
+// Mock some code in usb-backend.c
+#define spice_usbredir_write_callback mock_spice_usbredir_write_callback
+#define spice_channel_get_state mock_spice_channel_get_state
+#include "../src/usb-backend.c"
 
 #include "usb-device-cd.h"
-#include "usb-emulation.h"
 
 static SpiceUsbBackendDevice *device = NULL;
 
@@ -67,6 +70,150 @@ static void multiple(const void *param)
     spice_usb_backend_delete(be);
 }
 
+static unsigned int messages_sent = 0;
+static unsigned int hellos_sent = 0;
+static SpiceUsbBackendChannel *usb_ch;
+
+int
+mock_spice_usbredir_write_callback(SpiceUsbredirChannel *channel, uint8_t *data, int count)
+{
+    ++messages_sent;
+    g_assert_cmpint(count, >=, 4);
+    const uint32_t type = data[0] + data[1] * 0x100u + data[2] * 0x10000u + data[3] * 0x1000000u;
+    if (type == usb_redir_hello) {
+        ++hellos_sent;
+    }
+
+    // return we handled the data
+    spice_usb_backend_return_write_data(usb_ch, data);
+    return count;
+}
+
+// channel state to return from Mock function
+static enum spice_channel_state ch_state = SPICE_CHANNEL_STATE_UNCONNECTED;
+
+enum spice_channel_state
+mock_spice_channel_get_state(SpiceChannel *channel)
+{
+    return ch_state;
+}
+
+// number of GObjects allocated we expect will be freed
+static unsigned gobjects_allocated = 0;
+static void decrement_allocated(gpointer data G_GNUC_UNUSED, GObject *old_gobject G_GNUC_UNUSED)
+{
+    g_assert_cmpint(gobjects_allocated, !=, 0);
+    --gobjects_allocated;
+}
+
+#define DATA_START \
+    do { static const uint8_t data[] = {
+#define DATA_SEND \
+        }; \
+        spice_usb_backend_read_guest_data(usb_ch, (uint8_t*)data, G_N_ELEMENTS(data)); \
+    } while(0)
+
+static void attach(const void *param)
+{
+    const bool attach_on_connect = !!GPOINTER_TO_UINT(param);
+
+    hellos_sent = 0;
+    messages_sent = 0;
+    ch_state = SPICE_CHANNEL_STATE_UNCONNECTED;
+
+    SpiceSession *session = spice_session_new();
+    g_assert_nonnull(session);
+    g_object_weak_ref(G_OBJECT(session), decrement_allocated, NULL);
+    SpiceChannel *ch = spice_channel_new(session, SPICE_CHANNEL_USBREDIR, 0);
+    g_assert_nonnull(ch);
+    g_object_weak_ref(G_OBJECT(ch), decrement_allocated, NULL);
+    gobjects_allocated = 2;
+
+    /*
+     * real test, allocate a channel usbredir, emulate device
+     * initialization.
+     * Filter some call.
+     * Start sequence:
+     * - spice_usb_backend_new
+     * - spice_usb_backend_register_hotplug
+     * - spice_usb_backend_create_emulated_device
+     * - spice_usb_backend_channel_new
+     * - spice_usb_backend_channel_attach (if redir on connect)
+     * - spice_usb_backend_channel_flush_writes
+     * - spice_usbredir_write_callback
+     * - spice_usb_backend_return_write_data
+     * - spice_usb_backend_read_guest_data
+     * - spice_usb_backend_channel_attach (if not redir on connect)
+     */
+    GError *err = NULL;
+    SpiceUsbBackend * be = spice_usb_backend_new(&err);
+    g_assert_nonnull(be);
+    g_assert_null(err);
+    spice_usb_backend_register_hotplug(be, NULL, test_hotplug_callback, &err);
+    g_assert_null(err);
+
+    CdEmulationParams params = { "test-cd-emu.iso", 1 };
+    g_assert_true(create_emulated_cd(be, &params, &err));
+    g_assert_null(err);
+    g_assert_nonnull(device);
+
+    usb_ch = spice_usb_backend_channel_new(be, SPICE_USBREDIR_CHANNEL(ch));
+    g_assert_nonnull(usb_ch);
+
+    // attach on connect
+    ch_state = SPICE_CHANNEL_STATE_CONNECTING;
+    if (attach_on_connect) {
+        g_assert_true(spice_usb_backend_channel_attach(usb_ch, device, &err));
+        g_assert_null(err);
+    }
+    g_assert_cmpint(hellos_sent, ==, 0);
+    g_assert_cmpint(messages_sent, ==, 0);
+
+    // try to get initial data
+    ch_state = SPICE_CHANNEL_STATE_READY;
+    spice_usb_backend_channel_flush_writes(usb_ch);
+
+    // we should get an hello (only one!)
+    g_assert_cmpint(hellos_sent, ==, 1);
+    g_assert_cmpint(messages_sent, ==, 1);
+
+    // send hello reply
+    DATA_START
+        0x00,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //000 ....D.......
+        0x71,0x65,0x6d,0x75,0x20,0x75,0x73,0x62,0x2d,0x72,0x65,0x64, //00c qemu usb-red
+        0x69,0x72,0x20,0x67,0x75,0x65,0x73,0x74,0x20,0x33,0x2e,0x30, //018 ir guest 3.0
+        0x2e,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //024 .1..........
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //030 ............
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //03c ............
+        0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,                     //048 ........
+    DATA_SEND;
+
+    if (!attach_on_connect) {
+        g_assert_true(spice_usb_backend_channel_attach(usb_ch, device, &err));
+        g_assert_null(err);
+    }
+    g_assert_cmpint(hellos_sent, ==, 1);
+    g_assert_cmpint(messages_sent, >, 1);
+
+    // cleanup
+    spice_usb_backend_device_unref(device);
+    device = NULL;
+    spice_usb_backend_channel_delete(usb_ch);
+    usb_ch = NULL;
+    spice_usb_backend_deregister_hotplug(be);
+    spice_usb_backend_delete(be);
+
+    // this it's the correct sequence to free session!
+    // g_object_unref is not enough, causing wrong reference countings
+    spice_session_disconnect(session);
+    g_object_unref(session);
+    while (g_main_context_iteration(NULL, FALSE)) {
+        continue;
+    }
+
+    g_assert_cmpint(gobjects_allocated, ==, 0);
+}
+
 static void
 write_test_iso(void)
 {
@@ -87,6 +234,8 @@ int main(int argc, char* argv[])
 
     g_test_add_data_func("/cd-emu/simple", GUINT_TO_POINTER(1), multiple);
     g_test_add_data_func("/cd-emu/multiple", GUINT_TO_POINTER(128), multiple);
+    g_test_add_data_func("/cd-emu/attach_no_auto", GUINT_TO_POINTER(0), attach);
+    g_test_add_data_func("/cd-emu/attach_auto", GUINT_TO_POINTER(1), attach);
 
     return g_test_run();
 }
-- 
2.20.1

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/spice-devel




[Index of Archives]     [Linux Virtualization]     [Linux Virtualization]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]