libei/test/test-ei.c
Peter Hutterer c4601b7196 Implement device suspend/resume with starting state of "suspended"
This was already spelled out in the documentation but just not yet
implemented. New starting state for any device added by EIS is "suspended",
the server needs to explicitly resume it before events are accepted.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-08-20 14:44:38 +10:00

435 lines
11 KiB
C

#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include "util-munit.h"
#include "libei.h"
#include "eierpecken.h"
MUNIT_TEST(test_ei_ref_unref)
{
struct ei *ei = ei_new(NULL);
struct ei *refd = ei_ref(ei);
munit_assert_ptr_equal(ei, refd);
struct ei *unrefd = ei_unref(ei);
munit_assert_ptr_null(unrefd);
unrefd = ei_unref(ei);
munit_assert_ptr_null(unrefd);
/* memleak only shows up in valgrind */
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_immediately)
{
_cleanup_peck_ struct peck *peck = peck_new();
/* Client is immediately rejected */
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_REJECT_CLIENT);
peck_dispatch_until_stable(peck);
/* Expect the client to get a disconnect event */
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_connect)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_eis_client_ struct eis_client *client = NULL;
peck_dispatch_until_stable(peck);
with_server(peck) {
eis_dispatch(eis);
_cleanup_eis_event_ struct eis_event *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
client = eis_client_ref(eis_event_get_client(e));
eis_client_connect(client);
}
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *e =
peck_ei_next_event(ei, EI_EVENT_CONNECT);
}
with_server(peck) {
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *e =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_add_before_received)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_eis_client_ struct eis_client *client = NULL;
peck_dispatch_until_stable(peck);
with_server(peck) {
eis_dispatch(eis);
_cleanup_eis_event_ struct eis_event *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
client = eis_client_ref(eis_event_get_client(e));
eis_client_connect(client);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_device_ struct ei_device *device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_add(device);
}
/* We have *not* called eis_dispatch, so the device add hasn't been
* processed by the server yet */
with_server(peck) {
eis_client_disconnect(client);
}
/* But from the POV of the client we have added our devices, so we
* must receive a Removed event. */
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *removed =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
_cleanup_ei_event_ struct ei_event *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_add_after_received)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_eis_client_ struct eis_client *client = NULL;
peck_dispatch_until_stable(peck);
with_server(peck) {
eis_dispatch(eis);
_cleanup_eis_event_ struct eis_event *e = eis_get_event(eis);
munit_assert_ptr_not_null(e);
munit_assert_int(eis_event_get_type(e), ==, EIS_EVENT_CLIENT_CONNECT);
client = eis_client_ref(eis_event_get_client(e));
eis_client_connect(client);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_device_ struct ei_device *device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_add(device);
}
/* Receive the Added event but don't actually add the device */
peck_dispatch_eis(peck);
with_server(peck) {
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *removed =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
_cleanup_ei_event_ struct ei_event *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_remove_before_received)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_eis_client_ struct eis_client *client = NULL;
_cleanup_ei_device_ struct ei_device *device = NULL;
peck_dispatch_until_stable(peck);
with_server(peck) {
eis_dispatch(eis);
_cleanup_eis_event_ struct eis_event *e = eis_get_event(eis);
munit_assert_ptr_not_null(e);
munit_assert_int(eis_event_get_type(e), ==, EIS_EVENT_CLIENT_CONNECT);
client = eis_client_ref(eis_event_get_client(e));
eis_client_connect(client);
}
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_add(device);
}
/* server has the device now */
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_event_ struct ei_event *added =
peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED);
_cleanup_ei_event_ struct ei_event *resumed =
peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED);
ei_device_remove(device);
}
/* Disconnect before the server processed the Removed message. This
* does **not** trigger a EI_EVENT_REMOVED, the device has already
* been removed by the client.
*/
with_server(peck) {
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_remove_after_received)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_eis_client_ struct eis_client *client = NULL;
_cleanup_ei_device_ struct ei_device *device = NULL;
peck_dispatch_until_stable(peck);
with_server(peck) {
eis_dispatch(eis);
_cleanup_eis_event_ struct eis_event *e = eis_get_event(eis);
munit_assert_ptr_not_null(e);
munit_assert_int(eis_event_get_type(e), ==, EIS_EVENT_CLIENT_CONNECT);
client = eis_client_ref(eis_event_get_client(e));
eis_client_connect(client);
}
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_add(device);
}
/* server has the device now */
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_event_ struct ei_event *added =
peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED);
_cleanup_ei_event_ struct ei_event *resumed =
peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED);
ei_device_remove(device);
}
/* Disconnect after the server processed the Removed message. This
* does **not** trigger a EI_EVENT_REMOVED, the device has already
* been removed by the client.
*/
peck_dispatch_eis(peck);
with_server(peck) {
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_device_basics)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_ei_device_ struct ei_device *device = NULL;
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
/* device creation and getters/setters test */
with_client(peck) {
device = ei_device_new(ei);
munit_assert_not_null(device);
ei_device_configure_name(device, __func__);
munit_assert_string_equal(ei_device_get_name(device), __func__);
bool success = ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
munit_assert(success);
munit_assert(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER));
/* Add it, but we don't care about whether it worked correctly in this test */
ei_device_add(device);
/* Device is immutable after ei_device_add() */
bool failed_caps = ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
munit_assert(failed_caps == false);
munit_assert(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER));
}
/* Drain both sides, we don't care about the events themselves */
with_server(peck) {
peck_drain_eis(eis);
}
with_client(peck) {
peck_drain_ei(ei);
}
/* device is still immutable */
with_client(peck) {
bool failed_caps = ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
munit_assert(failed_caps == false);
munit_assert(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER));
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_device_add)
{
_cleanup_peck_ struct peck *peck = peck_new();
with_server(peck) {
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_eis(peck);
}
with_client(peck) {
peck_drain_ei(ei);
}
_cleanup_ei_device_ struct ei_device *device = NULL;
with_client(peck) {
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_add(device);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_event_ struct ei_event *event = ei_get_event(ei);
munit_assert_ptr_not_null(event);
munit_assert_int(ei_event_get_type(event), ==, EI_EVENT_DEVICE_ADDED);
struct ei_device *added = ei_event_get_device(event);
munit_assert_ptr_equal(device, added);
munit_assert(ei_device_has_capability(added, EI_DEVICE_CAP_POINTER));
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_device_add_drop_caps)
{
_cleanup_peck_ struct peck *peck = peck_new();
/* Device with pointer and keyboard caps but pointer is dropped */
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_POINTER);
peck_dispatch_until_stable(peck);
_cleanup_ei_device_ struct ei_device *device = NULL;
with_client(peck) {
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD);
ei_device_add(device);
}
peck_dispatch_eis(peck);
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *event = ei_get_event(ei);
munit_assert_ptr_not_null(event);
munit_assert_int(ei_event_get_type(event), ==, EI_EVENT_DEVICE_ADDED);
struct ei_device *d = ei_event_get_device(event);
munit_assert_ptr_equal(d, device);
munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_KEYBOARD));
munit_assert(!ei_device_has_capability(d, EI_DEVICE_CAP_POINTER));
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_device_add_zero_caps)
{
_cleanup_peck_ struct peck *peck = peck_new();
/* Device with pointer caps but those caps are rejected -> device
immediately removed by EIS */
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_POINTER);
peck_dispatch_until_stable(peck);
_cleanup_ei_device_ struct ei_device *device = NULL;
with_client(peck) {
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
ei_device_add(device);
}
peck_dispatch_eis(peck);
with_client(peck) {
ei_dispatch(ei);
_cleanup_ei_event_ struct ei_event *event = ei_get_event(ei);
munit_assert_ptr_not_null(event);
munit_assert_int(ei_event_get_type(event), ==, EI_EVENT_DEVICE_REMOVED);
}
return MUNIT_OK;
}
int
main(int argc, char **argv)
{
return munit_tests_run(argc, argv);
}