After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 722648 - Tests abort() even when -k,--keep-going is passed
Tests abort() even when -k,--keep-going is passed
Status: RESOLVED OBSOLETE
Product: glib
Classification: Platform
Component: gtest
unspecified
Other Linux
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2014-01-20 20:29 UTC by Emmanuele Bassi (:ebassi)
Modified: 2018-05-24 16:14 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
gtestutils: make TAP mode always run all tests (on unix) (14.22 KB, patch)
2014-12-14 13:30 UTC, Dan Winship
none Details | Review
gtestutils: make TAP mode always run all tests (on unix) (18.10 KB, patch)
2015-03-03 15:49 UTC, Dan Winship
none Details | Review

Description Emmanuele Bassi (:ebassi) 2014-01-20 20:29:57 UTC
g_assert() calls g_assertion_message_expr(), which always causes an abort().

even if g_assert() did call g_assertion_message(), the -k|--keep-going command line argument does not set test_nonfatal_assertions, which means that g_assertion_message() will still abort.

this breaks TAP suites pretty badly.
Comment 1 Dan Winship 2014-01-20 20:43:20 UTC
"-k" means "do not abort the program after the first test that calls g_test_fail()". (IOW, it is behaving as designed, it's just not designed to do something useful.)

The fact that g_assert() and g_assert_not_reached() always abort was also intentional, and I'm pretty sure it's because otherwise they can't be marked G_GNUC_NORETURN, and we don't want to remove that from them.
Comment 2 Dan Winship 2014-01-20 20:45:59 UTC
or probably not "can't be marked G_GNUC_NORETURN", but "if you mark them G_GNUC_NORETURN and then sometimes they return, there's no guarantee that the compiler will actually generate the right code".

Maybe we could have a #define to change their behavior, which could be used in test programs...
Comment 3 Dan Winship 2014-02-15 16:25:38 UTC
(In reply to comment #0)
> this breaks TAP suites pretty badly.

so, I think the fix for this is:

  1. --tap should imply -k

  2. if you run with --tap, and the test program does not call
     set_nonfatal_assertions(), then gtestutils should run each test
     as a separate process (reusing some of the g_test_trap_subprocess()
     infrastructure), so that the individual tests can happily crash
     without crashing the program as a whole.

This is not a compatible change though; programs that do setup/teardown stuff in main() (eg, setting up GTestDBus) will need to be changed to check g_test_subprocess() so they don't redo the setup for each child. So maybe we should add a new flag "--tap-all" for the new behavior, and update the glib-tap.mk stuff to pass that instead of --tap (so that then people won't get the new behavior until they import a new glib-tap.mk).
Comment 4 Dan Winship 2014-03-17 15:49:23 UTC
(In reply to comment #3)
>   2. if you run with --tap, and the test program does not call
>      set_nonfatal_assertions(), then gtestutils should run each test
>      as a separate process

Thought about this some more while playing with libsoup tests...

There's no reason to make this TAP-only, but it does need to be opt-in by the developer, either via an extra function call, or a param in g_test_init()'s varargs.

And I think this is definitely a better approach than g_test_set_nonfatal_assertions(), which sort of does the trick, but leads to really weird code like:

        foo = foo_new (x, y, z, &error);

        g_assert_no_error (error);
        g_clear_error (&error);

        g_assert_nonnull (foo);
        if (foo == NULL)
            return;

        ...

Emmanuele had talked about redefining the macros to be like:

        #define g_assert_nonnull(x) \
            if ((x) == NULL) { g_assertion_message (...); return; }

but that only works if all of your assertions are in the "top level" test functions, which isn't the case for me; I have lots of helper functions that get used by multiple tests.

Another possibility would be to turn all the assert macros into boolean expressions, so you could do:

        g_return_if_fail (g_assert_nonnull (foo));

and then make your helper functions return booleans too so you can do the same thing there.

But even if we do one of these, there's still the possibility that a bug in the library will unexpectedly cause a test to segv or divide by zero or something. So I think "run the test in a subprocess and just let it crash" is the best approach.
Comment 5 Emmanuele Bassi (:ebassi) 2014-03-30 21:38:46 UTC
(In reply to comment #4)

> But even if we do one of these, there's still the possibility that a bug in the
> library will unexpectedly cause a test to segv or divide by zero or something.
> So I think "run the test in a subprocess and just let it crash" is the best
> approach.

I think this should be the default for every test suite. yes, it makes it mildly inconvenient for a test suite that does set up/tear down, but it's the only sane way to do testing with the live grenade of abort() going off.

if we want to get conservative, we can use only if the --tap argument is given on the command line and fix the GDBus test suite if needed, but I cannot stress this enough: running a test suite that aborts under TAP is utterly, utterly broken, and against the whole point of the TAP support.
Comment 6 Dan Winship 2014-12-14 13:30:16 UTC
Created attachment 292694 [details] [review]
gtestutils: make TAP mode always run all tests (on unix)

When using --tap mode on unix, spawn a subprocess to do the actual
test running, and if it crashes, spawn a new one to pick up where the
first one left off.

Also, drop the "# Start of %s tests" / "#End of %s tests" messages in
the TAP output; they don't add much (since the full pathname of each
test is printed as it runs), and it would be slightly complicated to
not emit them redundantly in the respawning case.
Comment 7 Dan Winship 2014-12-14 13:41:57 UTC
So, this doesn't make any attempt to deal with the "program does lots of setup in main() before running g_test_run()" case, because I forgot about that while I was hacking on it... So something needs to happen there I guess. But even without that, it's pretty backward-compatible; it passes "make check" in GLib without needing any changes to any test programs.

(Possible hack; if --tap is passed, run the tests in a subprocess from g_test_init() rather than g_test_run(), and exit() at the end without ever running the rest of main()...)
Comment 8 Dan Winship 2015-03-03 15:49:02 UTC
Created attachment 298444 [details] [review]
gtestutils: make TAP mode always run all tests (on unix)

When using --tap mode on unix, spawn a subprocess to do the actual
test running, and if it crashes, spawn a new one to pick up where the
first one left off.

Also, drop the "# Start of %s tests" / "#End of %s tests" messages in
the TAP output; they don't add much (since the full pathname of each
test is printed as it runs), and it would be slightly complicated to
not emit them redundantly in the respawning case.
Comment 9 Allison Karlitskaya (desrt) 2015-03-03 16:06:27 UTC
I get the impression that this is going to interact pretty badly with people who do setup tasks in main()...
Comment 10 Dan Winship 2015-03-06 15:13:55 UTC
(In reply to Ryan Lortie (desrt) from comment #9)
> I get the impression that this is going to interact pretty badly with people
> who do setup tasks in main()...

Yes (comment 7).

I guess the easy fix would be to make g_test_run_in_subprocess() be a public function, and then you have to opt in by calling that instead of g_test_run().

But then we'd really need a better way to arrange for global setup/teardown. And ideally we'd want to run the global teardown function even if every actual test case crashed. But maybe now we're getting into "new-and-improved libgtest" territory.
Comment 11 GNOME Infrastructure Team 2018-05-24 16:14:46 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glib/issues/821.