Problem/Motivation
Simpletest.module assumes that a simpletest style test is a failure from a fatal error unless otherwise told it is passing: http://cgit.drupalcode.org/drupal/tree/core/modules/simpletest/src/TestB...
When phpunit fatal errors, it creates a 0 byte xml file in /sites/default/files/simpletest/phpunit-xx.xml. When it comes time to parse that output (http://cgit.drupalcode.org/drupal/tree/core/modules/simpletest/simpletes...), In line 673 it checks and if the file is 0- bytes, it simply bails out.
This causes the test to get "lost" with no record of that test either passing or failling. The legacy testbots look for "Fatal Error" in the output of the run and if it finds it, sets the whole test to a "Failing" state, but does not contain any indication of which particular test failed: (e.g.: https://www.drupal.org/node/2337191#comment-10205585)
The drupalci testbots will also have to implement this functionality to avoid 'passing' a failing test along, but it would be ideal to eventually have this handled properly in the simpletest module.
What I propose is that we create a default junit xml formatted 'failure' file in simpletest_phpunit_run_command().(http://cgit.drupalcode.org/drupal/tree/core/modules/simpletest/simpletes...) that would then get overwritten on a successful execution of that particular test run, that way it mimics the behavior of the simpletest style tests, and gives us the ability to know which specific unit test aborted on a Fatal Error.
Proposed resolution
Check for the return code on the executed phpunit file. If its not 0, an error occured and we can provide a special "xml" with that failure included.
Remaining tasks
User interface changes
API changes
Data model changes
Beta phase evaluation
Issue category | Bug/Task/Feature because ... |
---|---|
Issue priority | Critical because broken tests aren't seen. |
Comment | File | Size | Author |
---|---|---|---|
#41 | 2560643-41.patch | 1.58 KB | dawehner |
#41 | interdiff.txt | 2.86 KB | dawehner |
#35 | phpunit-2560643.35.patch | 4.43 KB | larowlan |
#35 | interdiff.txt | 733 bytes | larowlan |
#26 | interdiff.txt | 1.6 KB | chx |
Comments
Comment #2
MixologicComment #3
dawehnerHow feasible would it be to run the phpunit tests via the phpunit executable at that point? I guess jenkins would already have support for all that.
Comment #4
dawehnerTried to start with that, but the problem is that PHPUnit opens up that file and overwrites it in http://cgit.drupalcode.org/drupal/tree/core/vendor/phpunit/phpunit/src/U...
Comment #5
MixologicOkay, re #3 The phpunit executable needs to run in isolation mode, but the issue there is also, we do not have any sort of handling for phpunit's own executable when it encounters a fatal error. Putting this into simpletest allows us to have a wrapper around phpunit that can handle those anomolies.
I figured out a good place to put this - after the parsing of the output takes place.
Attached is a first stab at this. Im not too savvy with how to write a test that proves that a failing phpunit test breaks, so hoping somebody else can help with that.
With manual testing I've show this to work.
Comment #6
MixologicSome additional info on the patch. Yes, '.' does seem to be the return value when there is an error and phpunit does not return.
Comment #7
MixologicComment #8
dawehnerMHH doesn,'t "." mean something broke on the first test, but there might be more. Can't you look at the return value 0, 1, etc?
Comment #9
mradcliffeThe exec() command in simpletest_phpunit_run_command() needs to have the the optional 3rd argument which has the execution status. Then that var can be checked for 1/0 as @dawehner suggests in #8.
I am not sure what the behavior of return_var is on non-unix systems.
Comment #10
MixologicFixed to incorporate #8/#9
Also attached is a patch which shows how some deliberately broken tests would actually get caught as broken.
Im going to hope that '0' is success on non-unix.
Comment #11
chx CreditAttribution: chx commentedPlease do not credit me, this is a trivial change. Also, since this blocks DrupalCI, it blocks Drupal 8 so it's a critical.
Comment #12
webchickCan we add test coverage for this? This seems like the very definition of things we do not want to ever break again.
Comment #14
dawehnerI doubt we can/should test this at this level ... ideally for example we would use phpunit directly in which case the test failure would need to be caught on the level of DrupalCI, as this would execute that script.
Its hard to test the testing system, this is for sure.
Comment #15
mradcliffeI am not sure if simpletest_phpunit_run_command is testable. Maybe passing in garbage as $phpunit_file, and hope the command crashes, and assert that ret is non-zero?
Comment #16
dawehnerWell to be clear, there might be a chance to test it now, but on the longrun we really should move away from having a
simpletest(phpunit())
wrapping construct,as it makes things problematic. Once we have that not any longer, the test we will introduce here, won't work any longer.
Comment #17
MixologicUploading the "this is what the tests look like without this fix, but with the same breakage" - its the best I can think of for a test of this. What we should see is invisible fails, it might even come back greeen. but the log will show all the problems.
Comment #18
MixologicAlrighty then. #17 came back green, despite function calls to conjunction_junction_undefined_function(), a recursion, and a deliberate segfault (see the console log here: https://dispatcher.drupalci.org/job/default/13343/consoleFull)
So hopefully that demonstrates the kinds of broken that the patch is supposed to fix (as seen in #10) and also demonstrates that the patch wont break anything else (as seen in #10 and #11.
Comment #19
chx CreditAttribution: chx commented@webchick your wish is my command. Here's a test.
Comment #21
chx CreditAttribution: chx commentedOh bother, a missing @group.
Edit:
preg_match('/(.(?!b))*/', str_repeat("a", 10000));
is from http://ilia.ws/archives/5_Top_10_ways_to_crash_PHP.html -- it causes a segfault immediately. If a standalone PCRE library is chosen AND the --disable-stack-for-recursion option is given at compilation THEN this will not segfault. However, this is extremely unpopular (and no distributions ship with it) as it slows down PCRE for the sake of what is simply known as degenerate regexps. You can test by runningpcretest -C | grep 'Match recursion'
it will say (if you have a standalone PCRE install, that is)Match recursion uses stack
.Edit2: this is better than using
bananas()
to cause a fatal error because shutdown functions still might run after a fatal error. Nothing runs after the process itself is aborted this way. We can't abort reliably normally as exit/die will also run destructors and shutdown functions. Alternatively we could use$pid = getmypid(); exec("kill $pid"); exec("TSKILL $pid");
to get the OS to terminate the process immediately. Hopefully PHPunit won't add signal handlers... (it doesn't have one now).Comment #25
dawehnerCan we have a quick one line comment what we do here?
public ...
This one loads code so we need additional annotations, see IRC
Comment #26
chx CreditAttribution: chx commentedComment #27
dawehnerThank you. Otherwise we would have had another major, at least. You really don't want to break a workflow committers use.
Ran the phpunit tests manually:
Perfect, thank you!
This is needed in order to avoid #2565971: failures running phpunit from command line.
Comment #30
chx CreditAttribution: chx commentedUnfollowing the issue: I had a green patch then came phpunit annotations and I can't reproduce the fail locally from running the test alone with phpunit, running the simpletest group with phpunit or running the test with simpletest. It always passes. I can't and won't fight phpunit, I let others do that. I was against shoveling in PHPunit without documentation, education and proper integration and now this is going to block the RC There was no comparison between modern testing framework done, we just added PHPunit just because. Well done.
Edit: I reported two years ago that the integration is broken #2096615: Testbot does not return PHPunit fails properly. PHPunit is still unmaintained and the integration never got fixed.
Comment #31
larowlanWith Drupal CI we can run these outside simpletest right?
Comment #32
dawehnerPast is past and time is limited.
I asked for this additional annotations because otherwise state will leak into the tests running. Test failures like #2565971: failures running phpunit from command line. are hard to debug and should be prevented
in beforehand. We have more criticals to solve, no reason to freak out :( It burns everyone out, who is involved in the process!
You might have the right idea, get rid of the integration and rely on running phpunit directly. Its IMHO the only thing we can and should do!
#2566767: Don't allow running phpunit-based tests via the UI is the first issue of that kind. @Mixologic how difficult is it to run the phpunit tests separate?
I tried to use the drupalci_testrunner, but it turns out, I can't install it at the moment.
Feel free to commit #21 + the comments and maybe create a follow up?
Comment #33
larowlanThis is the fail (getting it locally)
Code I used to run it locally
Comment #34
larowlanThe issue is in \PHPUnit_Util_PHP::processChildResult
Comment #35
larowlanMoar isolation
This passes locally
Comment #36
dawehnerLet's hope it passes. This would be nice!
Comment #37
dawehnerlarowlan++
Comment #38
dawehnerWorked on the issue summary / beta eval, just to be sure.
Comment #39
alexpottWell since I run all the phpunit tests before I commit most patches we don't actually have any broken tests but it is certainly critical that our test infrastructure does not pick up all test fails. Nice that this comes with a test. However the test does not work for me or @dawehner since the changes in #35. In fact it works as expected without those changes. I don't get why those change matter one jot - this is a totally separate invocation of phpunit so it is already isolated BUT it should not matter if it is. My recommendation here is to remove the tests and add a major followup to add them in when we can get them to work consistently for everyone.
Comment #40
dawehner#2566963: Follow up of 2560643 Add test coverage is the needed follow up
Comment #41
dawehnerThere we go, removed the tests
Comment #42
webchickSince this is the exact same patch that already passed above, moving to RTBC.
Comment #43
alexpottCommitted c27852c and pushed to 8.0.x. Thanks!