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

Victor Toso victortoso at redhat.com
Tue Aug 27 14:02:47 UTC 2019


Hi,

On Tue, Aug 27, 2019 at 10:22:43AM +0100, Frediano Ziglio wrote:
> 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 at redhat.com>
> ---
>  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

I wonder if isn't better to create a -private header for this
instead?

> +#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;

Should we have different 'hellos' in the future? Let's say we
support 3.0 but not 3.1, etc.

> +
> +    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);

Not much to complain actually, happy again that we have this
tested. Lots of pre increment/decrement. I don't care much but
that's not that common in the client, I think.

>  
>      return g_test_run();
>  }
> -- 
> 2.20.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20190827/9bfedab1/attachment.sig>


More information about the Spice-devel mailing list