Discovered in #2171683: Remove all Simpletest overrides and rely on native multi-site functionality instead
Problem
-
Drupal\views\Tests\Plugin\DisplayFeedTest passes tests, but the internal browser actually shows a fatal error in the web page output:
Fatal error: Call to a member function hasPath() on a non-object in ViewListController::getDisplayPaths()
Details
- DisplayBag may return NULL in ViewsListController::getDisplayPaths().
- Not caused by a missing module dependency. The views_test module is enabled when ViewsListController iterates over the DisplayBag.
- First assumed the failure would be caused by an outdated/malformed views test config file, but that wasn't the case.
-
Now, the actual assertions in the feed display test did actually pass. The test only happens to contain an initial straw drupalGet() to the basic edit page of the test view (without any comments or assertions), and only on that edit page, a fatal error is triggered.
-
Studying the code of DisplayBag and PluginBag, there are various conditions in which the Iterator can return NULL instead of a plugin instance. When manually iterating over a PluginBag, the loop has to take that possibility into account.
-
The foreach loop over DisplayBag in ViewListController::getDisplayPaths() did not care for that, so simply checking for whether the Iterator yielded NULL instead of a display appears to be the adequate fix.
-
This was revealed by #2171683: Remove all Simpletest overrides and rely on native multi-site functionality instead, since the Simpletest fatal error.log is set up much earlier with that, so fatal errors in new-style controllers are actually caught.
| Comment | File | Size | Author |
|---|---|---|---|
| #18 | interdiff-2189453-18.txt | 650 bytes | damiankloip |
| #18 | 2189453-18.patch | 3.62 KB | damiankloip |
| #12 | interdiff-2189453-12.txt | 2.7 KB | damiankloip |
| #12 | 2189453-12.patch | 3.53 KB | damiankloip |
Comments
Comment #2
sunAlright, tested + confirmed that this also happens in HEAD.
As mentioned in the issue summary, the fatal error is not caught, because the fatal error.log for tests is set up too late for new-style controllers.
Attaching two patches: Complete patch + regression test only.
Comment #3
sunFWIW, #1778942: Discovery::getDefinition() / getDefinitions() : inconsistent return values for "no result" harmonized the Plugin StackDiscovery to return NULL (for non-existent plugins).
#2053313: Plugins do not gracefully handle missing definitions notices the overall problem space for plugins and seeks for a generic solution.
Comment #4
dawehnerWe should at least write something to the watchdog if a display on the actual frontend does not exists,
as hiding this fact is a bad idea.
Comment #5
dawehnerMaybe we should also try to skip invalid plugins on the iterator.
Comment #6
damiankloip commentedFirst of all, good find!
It kind of is, the actual fatal is not coming from the 'test_display_feed' view, but from the 'content_recent' view in the test. The block module is not enabled, but node is is. And the content_recent view has configuration for a view display.
I think this needs to be fixed in the actual pluginBag class, otherwise you will need to check for this every time you iterate over some plugin bag class.
I think something like this. Not sure if this is best, as get() will get called again but checking anything in current() is too late, so valid() makes the most sense from that point of view. This is only during iteration too, we lose nothing on single get() calls.
EDIT: Oh, didn't realise Daniel just posted here too (just looked at comment number and posted patch). Seems he had a similar idea of where the fix should live.
Comment #9
sunIt looks like the approach of the patch in #6 could work without too much pain, too — only two fatal errors across the core test suite.
Most likely, those two are caused by bogus test configuration or bogus test expectations.
Lastly, I think a code comment on the adjusted iterator line would help readers to understand why that is done. Also, not sure whether the parenthesis around the conditions are necessary?
Comment #10
sunUnless we go with the originally proposed patch, I have to unassign myself, as I'm not familiar with the code that you are touching :-)
Because this issue is seemingly blocking the parent issue, #2171683: Remove all Simpletest overrides and rely on native multi-site functionality instead, I'd love to see this getting fixed as soon as possible. — I wish I could be of more help... That said, according to our issue priority documentation, a fatal error means critical, so let me bump the priority accordingly.
Comment #11
damiankloip commentedOk, no worries :) let me fix the remaining tests.
Comment #12
damiankloip commentedOK, let's see how this gets on.
It was indeed a bogus test - The setupPluginBag method was creating a value map to return the plugin. However, because the setConfiguration method was changing the configuration data for that plugin, the plugin map did not match both parameters anymore, so returned NULL. I have switched this to use a returnCallback instead.
Parenthesis weren't necessary but I tend to favour that, as visually it is easier to follow the conditions. Anyway, meh - I've reverted that change :)
Comment #14
damiankloip commented12: 2189453-12.patch queued for re-testing.
Seems like another random one (UserCancelTest).
Comment #15
dawehner+1 for checking on this level.
Comment #16
webchickCatch asked for this one to be split off, so assigning to him.
Comment #17
catchThis needs a @todo to remove when #2080823: Create API to discover config entities' soft dependencies and use this to present a confirm form on module uninstall is fixed. Silently eating errors like this makes for horrible debugging. Otherwise patch looks OK.
Comment #18
damiankloip commented@todo added.
Comment #19
catchComment #20
catchCommitted/pushed to 8.x, thanks!