Problem/Motivation
In batch runs, when there is a fatal error, the current batch operation is invoked again, causing an "endless" loop (possibly eventually ended by a DB connection error). This may happen especially in the web-UI test runner during development, because WIP code is more likely to contain fatal errors.
This occurs since #2481453: Implement query parameter based content negotiation as alternative to extensions (#25)
Workaround: to run tests, use core/scripts/run-tests.sh rather than the web UI.
Proposed resolution
Remaining tasks
User interface changes
API changes
Data model changes
Original report by Arla
In web tests as well as kernel tests, when there is a fatal error, the test is run again from the beginning, causing an endless loop of test runs.
Drupal 8.0.0-beta8, 3700144
PHP 5.5.23, 5.5.26, 5.6.9, 5.6.4-4ubuntu6
MySQL 5.5.44, 5.6.25, 5.6.24-0ubuntu2
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | 2508888-25.patch | 382 bytes | jhedstrom |
| #18 | fatal_error_during_test-2508888-18.patch | 673 bytes | LKS90 |
Comments
Comment #1
arla commented@miro_dietiker spent some time debugging this. In short, if I understood it correctly, the batch system in this case fails to indicate sets as claimed and have it persisted for the next request. When the fatal error happens, the next batch request then claims the same item.
We could not identify a change that introduced this behaviour. We have been having it for a week or so.
We should create a tiny test that produces a fatal error, and then test different core checkouts and PHP/MySQL versions to pinpoint the critical conditions.
Comment #2
LKS90 commentedCan confirm this issue, already asked for some feedback on IRC but no luck there (someone tried reproducing it by adding some random characters to a file, that's actually not enough, calling a method on a non object is a reliable way to loop the test [or
$this->test()]where test() is not a valid function)Some information:
simpletest.modulewill run until line 325$test->run();and never finishes it's testing loop. The reason seems to be that the batch information is somehow lost between runs.Here is a screenshot of my database:
Fixing the fatal error completes the test, btw.
Comment #3
alexpottCan someone upload a do not test patch so people can replicate the issue without having to think too much.
To create a do not test patch add "do-not-test" before the .patch. For example "drupal.do_nothing_555555-do-not-test.patch"
Comment #4
LKS90 commentedHere is a patch. It adds a line to the
Form\ElementTest.And a screenshot of it looping:
Comment #5
LKS90 commentedComment #6
LKS90 commentedComment #7
arla commentedI just tried also with MySQL 5.5.44. Latest Drupal head as well as beta8. Fresh site installs after switching core version.
Now I have no idea what might be causing this behaviour. AFAIK I haven't changed my PHP version recently.
Comment #8
LKS90 commentedJust reproduced this with my patch at home. Forgot it was running...
Comment #9
LKS90 commentedComment #10
LKS90 commentedBut I just managed to have a PHP fatal error without the loop:
Comment #11
arla commentedTested older Drupal versions again, with PHP 5.5 and MySQL 5.6. Procedure:
This time, unlike in #7, I get the expected error for core checkouts 8.0.0-beta10 and 8.0.0-beta11, but not 8.0.x (6bb1ba3).
I will try to find the commit between beta11 and current head that causes this.
Comment #12
arla commentedWell this is strange.
On commit 8.0.0-beta11 it works, but on 7d532f7 it does not. The single change is:
How can changing the VERSION constant cause this? Can someone confirm?
Comment #13
LKS90 commentedCan confirm, works with beta11, broken in 7d532f7..., only difference seems to be the version constant.
Comment #14
LKS90 commentedManaged to cause a loop while not testing:
The batch page isn't happy about php fatal errors it seems.
Example: Search_API currently has broken indexing and uses the batch page for indexing. When adding a fatal error to Index::indexItems and clicking 'Index now' on /admin/config/search/search-api/index/default_index, the batch will never finish.
Comment #15
berdirI think this is related to either display_errors or xdebug being enabled.
Also strange.. When I just start a batch, it loops forever. But when I then manually refresh the page while it's looping, its' running once more and then displays the xdebug error message below the "An error happened" page.
Comment #16
dawehnerJust adding a tag
Comment #17
jhedstromWe'll want to test this.
Comment #18
LKS90 commentedHere is my try for a test for this error. It loops in the browser (unless you hit refresh), I think the testbot won't loop, but it won't reach the second assertion and have the standard test fail
The test did not complete due to a fatal error..Comment #19
LKS90 commentedSetting to needs review to get a testbot run for this patch.
Comment #22
jhedstromConfirmed the patch in #18 loops through the UI, and finishes from CLI (it doesn't pass on CLI though--we'll probably need a catchable fatal error, rather than an outright fatal which isn't catchable).
I also confirmed that the looping doesn't occur if
display_errorsis off (the batch response at that point is a 500). When turned on, the response is a 200! Enabling/disabling xdebug doesn't appear to impact.So, something in the batch system is changing the response code to a 200 if
display_errorsis turned on.Comment #23
berdir500 vs 200 is the standard PHP behavior for display_errors being on or off. No idea why it does that, but it AFAIK always behaved like this. I don't understand what changed in batch API, but somehow, we need to treat any response that can't be parsed as an error and abort, instead of trying to do something with it.
Comment #24
jhedstromGood to know!
I've tested this without JS, and it fails as expected upon encountering a fatal error. So, this is only an issue with the JS-processing of responses. I'll dig into this now.
Comment #25
jhedstromIt appears that the removal of
dataTypein the ajax request from #2481453: Implement query parameter based content negotiation as alternative to extensions. Is responsible. Without that parameter, the ajax method won't detect invalid json as a problem, and happily continue on even thoughprogress.statusandprogress.dataaren't set.Removing the 'needs tests' tag, because I don't think this will be reproducible without javascript tests.
This patch fixes the issue in my manual testing with the patch from #18 applied.
Comment #26
jhedstromComment #27
jhedstromSince this is a bug in
progress.js, this has wider implications than just testing. It could mask fatal errors during any other batch operation using JS.Comment #28
xjmRetitling per #27.
Comment #29
xjm@alexpott and I agreed on this being an RC target.
Comment #30
jhodgdonSeems like this is batch system and not simpletest.
Comment #31
jhodgdonWhat do we need to do to test this one-line patch and get it in?
Comment #32
arla commentedTested manually with LKS90's test from #18, but jhedstrom's fix in #25 does not fix it.
Again, for anyone testing this, please note that this bug occurs only in the Simpletest web UI, not when using run-tests.sh.
Comment #33
arla commentedUpdated IS.
Comment #34
jhedstromI just tried this again, and the issue still occurs, and the patch in #25 fixes it. To reproduce, and test the fix:
/admin/config/development/testingSimpleTestTestSimpleTestTestagain. The error is caught because the returned fatal error is invalid json:Comment #35
longwaveConfirmed that the test steps in #34 fix the problem.
I also confirmed this separately by introducing a deliberate fatal error in the Ubercart test suite. I had seen this issue before but was unsure of the cause - fatal errors cause the Simpletest UI to run in an infinite loop without the patch in #25, but with the patch in #25 tests with errors stop as expected with an error message after a single run.
Comment #36
arla commentedAh, yes, sorry for the sloppy testing. Didn't realise that the unpatched js was cached in the browser. I just tested again and I agree that #25 has a successful patch.
Comment #37
catchCommitted/pushed to 8.0.x, thanks!