Problem/Motivation

In #2927806: Use PHPUnit 6 for testing when PHP version >= 7.2 we introduced a method to install PHPUnit 6 if you run composer install when you have PHP7.2 and dev dependencies installed. This is because the current locked version of PHPUnit 4.8 is not compatible with PHP 7.2. The way this works is by triggering a post install command that can run a composer upgrade command. I think this is exceptionally risky. It means that we change the root composer.lock file on a composer install which is very very unexpected.

Proposed resolution

  • Don't do anything automatically on composer install.
  • If a user runs tests via run-tests.sh try to update to PHPUnit 6 if the PHP Version >= 7.2 if not successful exit and tell user about the problem.
  • If the user runs via ./vendor/bin/phpunit ensure the correct version of phpunit is being used.

Also considered was a solution similar to Symfony's where a completely separate version of phpunit is downloaded outside of vendor. We can't do this without removing PHPUnit as a dependency. This is because the PHPUnit classes Drupal's autoloader has access to would still be the 4.8 ones so this would be a complete mess.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

alexpott’s picture

Status: Active » Needs review
FileSize
3.77 KB

Here's one idea. I still think we should go the Symfony route and just get a completely different PHPUnit executable when we need too. This way we won't affect the root composer.lock ever.

mxr576’s picture

Can't we get rid of PHPUnit 4.8? Can someone describe me why this old, unsupported PHPUnit version is the minimum required version in Drupal 8.5.x still? (I'd be thankful for a link to an issue/discussion about this. I have not found anything.) Because PHP 5.5 support :(

alexpott’s picture

Issue summary: View changes
alexpott’s picture

Here's a new patch that works as per the issue summary. As we can't test the failure modes this needs manual testing. One concern I have is that calling out to composer can cause errors like

  [RuntimeException]
  Could not read /Users/alex/.composer/config.json
  file_get_contents(/Users/alex/.composer/config.json): failed to open stream: Permission denied

This doesn't matter if not update is required. The test will run as expected but if one is the update won't work. And the user will get the message "run-tests.sh requires the PHPUnit testing framework version 6 or greater when running on PHP 7.2 or greater. Please use 'composer run-script drupal-phpunit-upgrade' to ensure that it is present."
This problem occurs because we often run tests as a different user than the one that owns the files - we normally have to run the tests as the same users running the webserver. One way we could avoid it is if we check PHP version in run-tests.sh.

Status: Needs review » Needs work

The last submitted patch, 5: 2937469-4.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

alexpott’s picture

Status: Needs work » Needs review
FileSize
1.35 KB
5.86 KB

Ah we need the autoloader in place a little bit earlier.

alexpott’s picture

Adding a check to try to determine if the composer command is going to work without emitting errors and also improved the error message. Local testing looks good for me.

alexpott’s picture

So the file owner trick doesn't work for DrupalCI.

alexpott’s picture

What would I give for something similar to a .travis.yml file. So the approach in #9 does not work either. This should work. Ideally the testbot code would run a script provided by the package that can do things like run a composer package but we don';t have that yet.

I've also centralised the version checking to make it simpler to maintain.

alexpott’s picture

Mixologic’s picture

Ultimately the issue here is that we need to eliminate the lockfile for core.

If you do not have control over the production platform that your software is going to run in, you should not ship a lock file.

The vast majority of users who are using composer to build sites are ignoring that lock file anyhow, because they're using scaffold templates like https://github.com/drupal-composer/drupal-project. The only time the lockfile comes into play is if they want the added safety of ensuring they're on a tested version and use https://packagist.org/packages/webflo/drupal-core-strict.

So, what, beyond minimum and maximum dependency testing, do we need to do in order to not ship with a lock file? Anything else? I can prioritize that min/max testing if it would help us get to where there is no lock file.

alexpott’s picture

@Mixologic I totally agree. No lock file and highest / lowest dependency testing would be amazing. But we're not going to get there for 8.5.0 so rather than have the rather astonishing thing of doing a composer upgrade during a composer install I think we should just call composer upgrade from run-tests.sh under very special circumstances and inform users who run tests in PHP 7.2 what to do.

Mixologic’s picture

+++ b/core/scripts/run-tests.sh
@@ -463,6 +465,21 @@ function simpletest_script_init() {
+  // Detect if we're in the top-level process using the private 'execute-test'
+  // argument. Determine if being run on drupal.org's testing infrastructure
+  // using the presence of 'drupaltestbot' in the database url.
+  if (!$args['execute-test'] && preg_match('/drupaltestbot/', $args['dburl'])) {
+    // Update PHPUnit if needed and possible. There is a later check once the
+    // autoloader is in place to ensure we're on the correct version. We need to
+    // do this before the autoloader is in place to ensure that it is correct.
+    $composer = ($composer = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar`))
+      ? $php . ' ' . escapeshellarg($composer)
+      : 'composer';
+    passthru("$composer run-script drupal-phpunit-upgrade-check");
+  }

Whats the purpose of this block? i.e. is this really a drupalci feature request?

I'd definitely want to avoid guessing about whether or not we're on the testbot, as even that url has changed before. (also, I dont think drupaltestbot is in the dburl for sqlite)

alexpott’s picture

@Mixologic well it kind of is a DrupalCI request. As we've talked about before core needs a way to reliably run set up commands like this prior to a test run. And we need to be able to ship changes to these commands with different releases. The problem with saying okay let's change DrupalCI to call composer run-script drupal-phpunit-upgrade-check is that this script is only available in Drupal 8.5.x and not in 8.4.x. And what happens when we add something else. Or want to remove it. This is why CI's like travis and circle CI work so well is that they allow you to change and ship these commands as your needs change. So I'd rather hack something janky into our already janky run-tests.sh that is brittle until we have a more generic way of doing these things. Because this is definitely better than what is in HEAD.

Mixologic’s picture

As we've talked about before core needs a way to reliably run set up commands like this prior to a test run. And we need to be able to ship changes to these commands with different releases.

You have that now, albeit "reliably" is arguable. run-tests.sh is the build script for running core's tests, and the testbots will happily execute anything thats in there. This is definitely the rightest place to put these sorts of things, despite run-tests.sh jankyness. The one caveat is that if its something that would conflict with contrib testing, then it should be configurable, such that it'd only happen for core.

My question above was more of a why are you running the drupal-phpunit-upgrade-check exclusively on the testbot, and not in all environments?

I confirmed that the sqlite url doesnt have the u:p in it: --dburl "sqlite://localhost/sites/default/files/db.sqlite"

If you definitely need a reliable indicator that you're running in a testbot environment, I can definitely provide that directly, much like I added for the nightwatch testing: http://cgit.drupalcode.org/drupalci_testbot/tree/src/DrupalCI/Plugin/Bui...

(I should probably have that env be something like "BUILD_ENV" and use it universally)

This is why CI's like travis and circle CI work so well

The primary difference *there* is the poverty of being in a patch based workflow. Its hard to modify the build in a patch workflow as you almost have to double build, depending on what kinds of requirements changed. But theres nothing stopping us from doing whatever we want to the build, its just that it's always seemed like run-tests.sh was a thing we didnt want to touch.

alexpott’s picture

We can't run drupal-phpunit-upgrade-check because we can't guarantee that the test running user has permission to write files. Many users have to run tests as the user running the webserver and this user doesn't have the ability to write to vendor.

alexpott’s picture

Let's see if there are any existing env vars we can use.

alexpott’s picture

Here's a more reliable way I think. Not as good as a specific CI variable but we could do this with a follow-up to use it once implemented.

alexpott’s picture

Also @Mixologic nice catch re sqlite db testing.

Mile23’s picture

Make PHPUnit 4.8 the special case. Specify that core needs PHPUnit >=4.8 <7 (allow 4, 5, and 6). Put PHPUnit 6 in the lock file. Look for PHP versions < 7 and say composer update for those.

If we had a defined behavior for composer.json in modules, we'd be able to tell contrib to specify PHPUnit 4.8 if their tests aren't ready. But we can fake it because (IIRC) the testbot merges the facade's composer.json for the project, so it's almost the same. Contrib already has to deal with PHP 7.2+ so those projects should be updating their tests anyway.

I don't think we need to modify run-test.sh or anything, just flip the behavior of the composer script and then wait until we drop PHP <7. Then we just remove the special case from the composer script.

See also: https://github.com/sebastianbergmann/phpunit/releases/tag/7.0.0

Mile23’s picture

Make PHPUnit 4.8 the special case. Specify that core needs PHPUnit >=4.8 <7 (allow 4, 5, and 6). Put PHPUnit 6 in the lock file. Look for PHP versions < 7 and say composer update for those.

If we had a defined behavior for composer.json in modules, we'd be able to tell contrib to specify PHPUnit 4.8 if their tests aren't ready. But we can fake it because (IIRC) the testbot merges the facade's composer.json for the project, so it's almost the same. Contrib already has to deal with PHP 7.2+ so those projects should be updating their tests anyway.

I don't think we need to modify run-test.sh or anything, just flip the behavior of the composer script and then wait until we drop PHP <7. Then we just remove the special case from the composer script.

See also: https://github.com/sebastianbergmann/phpunit/releases/tag/7.0.0

alexpott’s picture

We can't do #21/#22 because then composer install will fail in PHP 5. Also we're not going to move PHP7 to PHPUnit6 prior to 8.5.0 so can we please do this to fix the composer weirdness before 8.5.0 comes out and causes major headaches.

catch’s picture

#19 looks viable but I think we should add a @todo and a follow-up to remove it for when we drop PHP 5.5 support.

alexpott’s picture

Mixologic’s picture

Status: Needs review » Reviewed & tested by the community

We definitely should avoid changing the results of composer.lock to avoid surprises. This is a much better way to accomplish this oddly required workaround until we can get a better system in place, and it works with the testbots as is.

LGTM.

  • catch committed 45cf042 on 8.6.x
    Issue #2937469 by alexpott, Mixologic: Automatic upgrade to PHPUnit 6 is...

  • catch committed effcfdb on 8.5.x
    Issue #2937469 by alexpott, Mixologic: Automatic upgrade to PHPUnit 6 is...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.6.x and cherry-picked to 8.5.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.