Capture stdout/stderr from GTestDBus's dbus-daemon
@tvb
Submitted by Tristan Van Berkom Assigned to David Zeuthen
Link to original bug (#695110)
Description
First, here is the basic problem statement.
When running test cases that use a GTestDBus in a fixture, I have tons of unrelated output printed to the console.
This makes it difficult to see which test failed if for instance, one test fails out of 20 cases executed in the same directory (in EDS we have about 20 test programs in one directory, each suite running an average of 4 cases each).
Here is the output of one of the single test programs with only two cases:
/EBookClient/AddContact/PreserveUid: Activating service name='org.gnome.evolution.dataserver.Sources1'
Successfully activated service 'org.gnome.evolution.dataserver.Sources1'
Activating service name='org.gnome.evolution.dataserver.AddressBook5'
Successfully activated service 'org.gnome.evolution.dataserver.AddressBook5'
OK
/EBookClient/AddContact/UidConflict:
(lt-evolution-addressbook-factory:13812): libebookbackend-WARNING **: Failed to add contacts: column uid is not unique
OK
PASS: test-client-preserve-uid
First, note that because of problems in EDS that need fixing, we use a single GTestDBus for the entire suite because currently we can't dispose the GTestDBus object at fixture teardown time.
When that bug gets fixed, the above, irrelevant output printed to the console will double.
I've written a little hack for GTestDBus which captures the child stdout/stderr of the dbus-daemon, when ignoring the output the test case outputs this instead:
/EBookClient/AddContact/PreserveUid: OK
/EBookClient/AddContact/UidConflict: OK
PASS: test-client-preserve-uid
Much nicer, however the hack I've implemented (which just ignores the stdout/stderr) is not really sufficient.
You'll notice that the above warning is not printed: (lt-evolution-addressbook-factory:13812): libebookbackend-WARNING **: Failed to add contacts: column uid is not unique
In this case it's a good thing, because the test in question (UidConflict) explicitly tests a case where adding a contact should fail with a specific error code, and we want the server to log the error with a g_warning(), but we don't want that irrelevant output printed to the console while running tests.... so far so good.
But the reason that this approach is insufficient is because we ideally would want to see the stderr/stdout in the case that a test case fails (as this could be a good immediate indication as to why it failed).
So, what I would propose, is some added apis to GTestDBus.. here's a first draft of the idea:
/* These should be called optionally, only before g_test_dbus_up()
- if they are called, then a GIOChannel is setup to capture the output
- streams of the dbus-daemon started for this test case */ void g_test_dbus_capture_stdout (GTestDBus *self); void g_test_dbus_capture_stderr (GTestDBus *self);
/* These would read back any data on the stdout/stderr
- pipes from the underlying dbus-daemon */ gboolean g_test_dbus_read_stdout (GTestDBus *self, gchar **output, gint *len, GError **error); gboolean g_test_dbus_read_stderr (GTestDBus *self, gchar **output, gint *len, GError **error);
Having apis like this would allow one to write test cases that would print the server stdout/stderr for a given test case... only in the case that a test failed.
There's one thing I'm not 100% sure about, depending on the implementation of g_spawn_async_with_pipes(), the buffered pipes will start to block the server processes once they reach 8192 bytes, so it's possible that GTestDBus needs to progressively accumulate stdout/stderr into a local buffer while the test is in progress (which means an additional thread/main context needs to run while the daemon is 'up', probably we don't need the GError in the above API as well).
Thoughts ?