Skip to content

Commit

Permalink
Add umockdev_testbed_wait_script()
Browse files Browse the repository at this point in the history
Script replay happens in the background in a thread. This API waits for
a script (or evemu events, which are translated to scripts) to finish,
so that tests can synchronize them with other system events.

Fixes #247
  • Loading branch information
martinpitt committed Dec 22, 2024
1 parent 1a712ac commit 8d99dd1
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/umockdev.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,28 @@ public class Testbed: GLib.Object {
return true;
}

/**
* umockdev_testbed_wait_script:
* @self: A #UMockdevTestbed.
* @dev: Device path (/dev/...) to wait for
* @error: return location for a GError, or %NULL
*
* Wait for a previously loaded script or evemu record to finish.
*
* Returns: %TRUE on success, %FALSE if @dev is invalid and an error
* occurred.
*/
public bool wait_script (string dev)
throws FileError
{
unowned var runner = this.dev_script_runner.lookup (dev);
if (runner == null)
throw new FileError.NOENT (dev + " has no active script runner");
runner.wait ();
this.dev_script_runner.remove (dev);
return true;
}

/**
* umockdev_testbed_load_socket_script:
* @self: A #UMockdevTestbed.
Expand Down Expand Up @@ -1772,6 +1794,18 @@ private class ScriptRunner {
this.thread.join ();
}

public void wait ()
{
if (!this.running) {
debug ("Script runner for %s already finished, nothing to wait for", this.device);
return;
}

debug ("Waiting for script runner for %s to finish", this.device);
this.thread.join ();
assert (this.running == false);
}

private void* run ()
{
char op;
Expand Down
65 changes: 65 additions & 0 deletions tests/test-umockdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,11 @@ r 0 ^@^^^`^@a\n";
/* end of script */
ASSERT_EOF;

/* waiting is a no-op */
success = umockdev_testbed_wait_script(fixture->testbed, "/dev/greeter", &error);
g_assert(success);
g_assert_no_error(error);

close(fd);
}

Expand Down Expand Up @@ -1830,6 +1835,64 @@ r 0 OK\n";
close(fd);
}

static void
t_testbed_script_replay_wait(UMockdevTestbedFixture * fixture, UNUSED_DATA)
{
gboolean success;
GError *error = NULL;
g_autofree char *tmppath = NULL;
int fd;
char buf[1024];

static const char* test_script = "r 100 Hello \n\
r 100 world\n";

umockdev_testbed_add_from_string(fixture->testbed,
"P: /devices/greeter\nN: greeter\n"
"E: DEVNAME=/dev/greeter\nE: SUBSYSTEM=tty\nA: dev=4:64\n", &error);
g_assert_no_error(error);

/* write script into temporary file */
fd = g_file_open_tmp("test_script_simple.XXXXXX", &tmppath, &error);
g_assert_no_error(error);
g_assert_cmpint(write(fd, test_script, strlen(test_script)), >, 10);
close(fd);

/* load it */
success = umockdev_testbed_load_script(fixture->testbed, "/dev/greeter", tmppath, &error);
g_assert_no_error(error);
g_assert(success);
g_unlink (tmppath);

/* wait for it; this writes the output into the pipe buffer, and theoretically may block
* take the risk for the unit test, it's small enough */
success = umockdev_testbed_wait_script(fixture->testbed, "/dev/greeter", &error);
g_assert(success);
g_assert_no_error(error);

/* start communication */
fd = g_open("/dev/greeter", O_RDWR, 0);
g_assert_cmpint(fd, >=, 0);

/* we get the full message in a single read */
g_assert_cmpint(read(fd, buf, sizeof buf), ==, 11);
g_assert_cmpint(memcmp(buf, "Hello world", 11), ==, 0);

close(fd);

/* device has no script any more */
success = umockdev_testbed_wait_script(fixture->testbed, "/dev/greeter", &error);
g_assert_false(success);
g_assert_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
g_clear_error(&error);

/* invalid device */
success = umockdev_testbed_wait_script(fixture->testbed, "/dev/invalid", &error);
g_assert_false(success);
g_assert_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
g_clear_error(&error);
}

static void
t_testbed_script_replay_socket_stream(UMockdevTestbedFixture * fixture, UNUSED_DATA)
{
Expand Down Expand Up @@ -2389,6 +2452,8 @@ main(int argc, char **argv)
t_testbed_script_replay_default_device, t_testbed_fixture_teardown);
g_test_add("/umockdev-testbed/script_replay_override_default_device", UMockdevTestbedFixture, NULL, t_testbed_fixture_setup,
t_testbed_script_replay_override_default_device, t_testbed_fixture_teardown);
g_test_add("/umockdev-testbed/script_replay_wait", UMockdevTestbedFixture, NULL, t_testbed_fixture_setup,
t_testbed_script_replay_wait, t_testbed_fixture_teardown);
g_test_add("/umockdev-testbed/script_replay_evdev_event_framing", UMockdevTestbedFixture, NULL, t_testbed_fixture_setup,
t_testbed_script_replay_evdev_event_framing, t_testbed_fixture_teardown);
g_test_add("/umockdev-testbed/script_replay_socket_stream", UMockdevTestbedFixture, NULL, t_testbed_fixture_setup,
Expand Down

0 comments on commit 8d99dd1

Please sign in to comment.