Problem/Motivation
Often one of the first four tests often fails on DrupalCI when using postgres. Whilst this is obviously is an issue for DrupalCI the way in which it fails shows that we have a problem in the installer.
Failing tests:
Action.Drupal\action\Tests\ConfigurationTest
✗ testActionConfiguration
fail: [Completion check] Line 31 of
core/modules/action/src/Tests/ConfigurationTest.php:
The test did not complete due to a fatal error.
✗ getDefinition
exception: [Uncaught exception] Line 796 of
vendor/symfony/dependency-injection/ContainerBuilder.php:
Symfony\Component\DependencyInjection\Exception\InvalidArgumentException:
The service definition "renderer" does not exist. in
Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition() (line
796 of
/var/www/html/vendor/symfony/dependency-injection/ContainerBuilder.php).
Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition('renderer')
Symfony\Component\DependencyInjection\ContainerBuilder->get('renderer')
Drupal::service('renderer')
install_database_errors(Array, './sites/simpletest/943579/settings.php')
install_verify_database_settings('sites/simpletest/943579')
install_begin_request(Object, Array)
install_drupal(Object, Array)
Drupal\simpletest\WebTestBase->doInstall()
Drupal\simpletest\WebTestBase->setUp()
Drupal\simpletest\TestBase->run(Array)
simpletest_script_run_one_test('5',
'Drupal\action\Tests\ConfigurationTest')
The backtrace shows that the early use of the renderer in install_database_error()
is problematic where the database settings are available for verification during the first call to install_verify_database_settings()
from install_begin_request()
.
We are using the renderer for several reasons - to format an item list and to use an inline twig template.
Proposed resolution
Check if the renderer service exists and only use it if it does - install_verify_database_settings()
only cares if the array returned is not empty - it does not care what is in it.
Remaining tasks
User interface changes
None
API changes
None
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#14 | 2662552-2-14.patch | 4.78 KB | alexpott |
#11 | 2662552-11.patch | 3.29 KB | dawehner |
#5 | 2662552-5.patch | 1.09 KB | alexpott |
#5 | 2-5-interdiff.txt | 833 bytes | alexpott |
#2 | 2662552-2.patch | 1.07 KB | alexpott |
|
Comments
Comment #2
alexpottUnfortunately this is completely untestable because it is super super early installer. But making this change might allow us to see what is going wrong with Postgres occasionally in the first tests run on DrupalCI.
Comment #4
catchnot having.
And wouldn't if ($errors) be enough?
But yes makes sense.
Error looks like the /vendor fallout.
Comment #5
alexpottHmmm... not my best sentence ever. The
if (count($errors)
is not really part of the part - kinda out-of-scope imo.Reported the /vendor issue to Mixologic.
Comment #8
xjmLooks like a good fix to me if we can get it through an actual test run.
Comment #9
xjmSo this was introduced in #2501835: Remove SafeMarkup::set in Drupal\Core\Database\Install\Tasks::runTasks() and ensure multiple messages are printed.
@alexpott and I discussed this patch. The problem is that install_database_errors() is used in two places, both SiteSettingsForm and install_verify_database_settings(), which happens very early in the installer. Part of the issue is that the return value of
install_database_errors()
is undocumented -- is it supposed to return just a list of errors, asinstall_verify_database_settings()
seems to expect? Or is it specifically a form error array of error markup, asSiteSettingsForm
expects? :Pinstall_verify_database_settings()
does not actually need any of the markup or even the text for the errors -- it just needs to know whether or not there were errors. So, we were wondering if we could move the actual markup/render building intoSiteSettingsForm
or something similar.@alexpott also pointed out that one of the other code paths in
install_database_errors()
runs Drupal\Core\Database\Install\Tasks::validateDatabaseSettings(), which also builds renderable/markup objects (in that caset()
strings) into a form error array structure.Comment #10
alexpottWe also have a potential problems with drush installation. If you add db information to settings.php with a incorrect prefix - for example
blah blha
then it'll produce the same error when you dodrush si
. However even with this fix the error you get when you do this is not helpful. You getDrupal\Core\Installer\Exception\AlreadyInstalledException
- funky :)Comment #11
dawehnerIts a bit hard to describe what I think, but I disagree with this fix. We are hiding errors. One example I played with is to set bad database credentials in settings.php.
An alternative approach could be to have a custom object which can be used as early as possible.
Comment #12
alexpott@dawehner we're not hiding errors ...
This method is called before the container is set up. And before errors could be presented to the user. And it only counts the errors to work out if there is an error.
Comment #14
alexpottBelieve or not we actually have test coverage of the inline template used here... see
Drupal\system\Tests\Installer\InstallerTranslationTest
Discussed at length with @xjm and a bit on IRC with @dawehner. Both are keen to move the use of render into
SiteSettingsForm
. I agree. Currentlyinstall_database_errors()
does two things; it discovers if there any database errors, it links these errors to form elements. I don't think we should considerinstall_database_errors()
API. It is only, and can only, ever been called by the installer whilst installing drupal.New approach and therefore no interdiff.
Comment #15
dawehnerThanks a ton alex! It is nearly always worth to do things the right way
Comment #17
xjmThanks @alexpott. That is much cleaner and the added documentation also will make this easier to understand in the future.
My one concern with this approach when @alexpott and I discussed it was that there is technically a slight BC break for
install_database_errors()
, if it were ever used outside of these two places in core. We're changing the expected contents of the return array. @alexpott and I tried to think of any usecase for this function outside of core, but could not come up with one. According to the D8 API policy, though, the installer is all considered internal API. I added this change record just in case we overlooked something: https://www.drupal.org/node/2677482I committed and pushed this to 8.1.x. For 8.0.x, we have a few options:
I can see cases for all three approaches, so setting PTBP for now for others' feedback. I am leaning toward the first.
Comment #18
xjmAlso, a followup to actually document
install_database_errors()
would not go amiss.Comment #19
xjmSince 8.0.x is about to be EOL, marking this fixed against 8.1.x.