test: add the ability to add offsets to ei_now()

Build a separate libei-eierpecken.so that is identical to libei.so but
allows adding an offset to ei_now() for the eierpecken tests. That
offset is added to the return value of ei_now(), removing the real-time
dependency of the tests.

In other words, we can call peck_ei_add_time_offset(peck, s2us(5)) to
add 5 seconds to the time and continue the test as if that time has
elapsed.
This commit is contained in:
Peter Hutterer 2023-11-08 13:59:21 +10:00
parent 7999483a34
commit 4e634aa76c
8 changed files with 146 additions and 36 deletions

View file

@ -113,6 +113,8 @@ struct ei {
enum ei_log_priority priority;
} log;
ei_clock_now_func clock_now;
bool is_sender;
};

View file

@ -896,19 +896,30 @@ ei_configure_name(struct ei *ei, const char *name)
ei->name = xstrdup(name);
}
_public_ void
ei_clock_set_now_func(struct ei *ei, ei_clock_now_func func)
{
ei->clock_now = func;
}
_public_ uint64_t
ei_now(struct ei *ei)
{
uint64_t ts = 0;
int rc = now(&ts);
if (rc < 0) {
/* We should probably disconnect here but the chances of this
* happening are so slim it's not worth worrying about. Plus,
* if this fails we're likely to be inside eis_device_frame()
* so we should flush a frame event before disconnecting and... */
log_error(ei, "clock_gettime failed: %s", strerror(-rc));
if (ei->clock_now)
ts = ei->clock_now(ei);
else {
int rc = now(&ts);
if (rc < 0) {
/* We should probably disconnect here but the chances of this
* happening are so slim it's not worth worrying about. Plus,
* if this fails we're likely to be inside eis_device_frame()
* so we should flush a frame event before disconnecting and... */
log_error(ei, "clock_gettime failed: %s", strerror(-rc));
}
}
return ts;
}

View file

@ -693,6 +693,24 @@ ei_log_set_priority(struct ei *ei, enum ei_log_priority priority);
enum ei_log_priority
ei_log_get_priority(const struct ei *ei);
/**
* Optional override function for ei_now().
*
* By default ei_now() returns the current timestamp in CLOCK_MONOTONIC. This
* may be overridden by a caller to provide a different timestamp.
*
* There is rarely a need to override this function. It exists for the libei-internal test suite.
*/
typedef uint64_t (*ei_clock_now_func)(struct ei *ei);
/**
* Override the function that returns the current time ei_now().
*
* There is rarely a need to override this function. It exists for the libei-internal test suite.
*/
void
ei_clock_set_now_func(struct ei *, ei_clock_now_func func);
/**
* Set the name for this client. This is a suggestion to the
* server only and may not be honored.
@ -802,8 +820,8 @@ ei_peek_event(struct ei *ei);
* @returns a timestamp in microseconds for the current time to pass into
* ei_device_frame().
*
* In the current implementation, the returned timestamp is CLOCK_MONOTONIC
* for compatibility with evdev and libinput.
* By default, the returned timestamp is CLOCK_MONOTONIC for compatibility with
* evdev and libinput. This can be overridden with ei_clock_set_now_func().
*/
uint64_t
ei_now(struct ei *ei);

View file

@ -72,6 +72,8 @@ struct eis {
enum eis_log_priority priority;
} log;
eis_clock_now_func clock_now;
const struct eis_proto_requests *requests;
};

View file

@ -424,18 +424,30 @@ eis_add_client(struct eis *eis, struct eis_client *client)
list_append(&eis->clients, &client->link);
}
_public_ void
eis_clock_set_now_func(struct eis *eis, eis_clock_now_func func)
{
eis->clock_now = func;
}
_public_ uint64_t
eis_now(struct eis *eis)
{
uint64_t ts = 0;
int rc = now(&ts);
if (rc < 0) {
/* We should probably disconnect here but the chances of this
* happening are so slim it's not worth worrying about. Plus,
* if this fails we're likely to be inside ei_device_frame()
* so we should flush a frame event before disconnecting and... */
log_error(eis, "clock_gettime failed: %s", strerror(-rc));
if (eis->clock_now)
ts = eis->clock_now(eis);
else {
int rc = now(&ts);
if (rc < 0) {
/* We should probably disconnect here but the chances of this
* happening are so slim it's not worth worrying about. Plus,
* if this fails we're likely to be inside ei_device_frame()
* so we should flush a frame event before disconnecting and... */
log_error(eis, "clock_gettime failed: %s", strerror(-rc));
}
}
return ts;
}

View file

@ -439,6 +439,24 @@ eis_log_set_priority(struct eis *eis, enum eis_log_priority priority);
enum eis_log_priority
eis_log_get_priority(const struct eis *eis);
/**
* Optional override function for eis_now().
*
* By default eis_now() returns the current timestamp in CLOCK_MONOTONIC. This
* may be overridden by a caller to provide a different timestamp.
*
* There is rarely a need to override this function. It exists for the libeis-internal test suite.
*/
typedef uint64_t (*eis_clock_now_func)(struct eis *eis);
/**
* Override the function that returns the current time eis_now().
*
* There is rarely a need to override this function. It exists for the libeis-internal test suite.
*/
void
eis_clock_set_now_func(struct eis *, eis_clock_now_func func);
struct eis *
eis_ref(struct eis *eis);
@ -1594,11 +1612,11 @@ eis_event_touch_get_y(struct eis_event *event);
* @returns a timestamp for the current time to pass into
* eis_device_frame().
*
* In the current implementation, the returned timestamp is CLOCK_MONOTONIC
* for compatibility with evdev and libinput.
* By default, the returned timestamp is CLOCK_MONOTONIC for compatibility with
* evdev and libinput. This can be overridden with eis_clock_set_now_func().
*/
uint64_t
eis_now(struct eis *ei);
eis_now(struct eis *eis);
/**
* @}

View file

@ -86,6 +86,9 @@ struct peck {
bool ei_fatal_bugs;
bool eis_fatal_bugs;
uint64_t ei_time_offset;
uint64_t eis_time_offset;
};
static const uint32_t INDENTATION = 4;
@ -105,6 +108,40 @@ peck_dedent(struct peck *peck)
static
OBJECT_IMPLEMENT_GETTER(peck, indent, uint32_t);
static uint64_t
peck_ei_now_func(struct ei *ei)
{
static uint64_t offset = 0;
struct peck *peck = ei_get_user_data(ei);
if (peck->ei_time_offset != offset) {
offset = peck->ei_time_offset;
log_debug(peck, "Time is now offset by %" PRIu64"us\n", offset);
}
uint64_t ts = 0;
now(&ts);
return ts + peck->ei_time_offset;
}
static uint64_t
peck_eis_now_func(struct eis *eis)
{
static uint64_t offset = 0;
struct peck *peck = eis_get_user_data(eis);
if (peck->eis_time_offset != offset) {
offset = peck->eis_time_offset;
log_debug(peck, "Time is now offset by %" PRIu64"us\n", offset);
}
uint64_t ts = 0;
now(&ts);
return ts + peck->ei_time_offset;
}
static void
peck_destroy(struct peck *peck)
{
@ -147,6 +184,20 @@ peck_destroy(struct peck *peck)
}
}
void
peck_ei_add_time_offset(struct peck *peck, uint64_t us)
{
log_debug(peck, "Adding ei time offset of %" PRIu64 "us\n", us);
peck->ei_time_offset += us;
}
void
peck_eis_add_time_offset(struct peck *peck, uint64_t us)
{
log_debug(peck, "Adding EIS time offset of %" PRIu64 "us\n", us);
peck->eis_time_offset += us;
}
static
OBJECT_IMPLEMENT_CREATE(peck);
OBJECT_IMPLEMENT_UNREF(peck);
@ -270,32 +321,20 @@ peck_ei_get_default_touch(struct peck *peck)
};
/* Ensures that device frames in tests always have an ascending and fixed
* interval. We start with 30 * interval in the past, every event then goes
* forward by 10ms.
*
* Tests that have more than 30 events will run into the future with their
* timestamps, shouldn't be an issue for the test suite though.
* interval. Every time this is called it adds 10ms to the time offset.
*/
uint64_t
peck_ei_now(struct peck *peck)
{
const uint32_t interval = ms2us(10);
const uint32_t past_offset = interval * 30;
peck->now = peck->now == 0 ? ei_now(peck->ei) - past_offset : peck->now + interval;
return peck->now;
peck_ei_add_time_offset(peck, ms2us(10));
return ei_now(peck->ei);
}
uint64_t
peck_eis_now(struct peck *peck)
{
const uint32_t interval = ms2us(10);
const uint32_t past_offset = interval * 30;
peck->now = peck->now == 0 ? eis_now(peck->eis) - past_offset : peck->now + interval;
return peck->now;
peck_eis_add_time_offset(peck, ms2us(10));
return eis_now(peck->eis);
}
void
@ -439,6 +478,7 @@ new_context(enum peck_ei_mode ei_mode)
struct eis *eis = eis_new(peck);
eis_log_set_handler(eis, peck_eis_log_handler);
eis_log_set_priority(eis, EIS_LOG_PRIORITY_DEBUG);
eis_clock_set_now_func(eis, peck_eis_now_func);
rc = eis_setup_backend_fd(eis);
munit_assert_int(rc, ==, 0);
fd = eis_backend_fd_add_client(eis);
@ -451,6 +491,7 @@ new_context(enum peck_ei_mode ei_mode)
ei_set_user_data(ei, peck);
ei_log_set_handler(ei, peck_ei_log_handler);
ei_log_set_priority(ei, EI_LOG_PRIORITY_DEBUG);
ei_clock_set_now_func(ei, peck_ei_now_func);
ei_configure_name(ei, "eierpecken test context");
rc = ei_setup_backend_fd(ei, fd);
munit_assert_int(rc, ==, 0);

View file

@ -167,6 +167,12 @@ peck_eis_disable_fatal_bug(struct peck *peck);
void
peck_eis_enable_fatal_bug(struct peck *peck);
void
peck_ei_add_time_offset(struct peck *peck, uint64_t us);
void
peck_eis_add_time_offset(struct peck *peck, uint64_t us);
void
peck_enable_eis_behavior(struct peck *peck, enum peck_eis_behavior behavior);