-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PHPUnit 9+ (for PHP 8 support) #10019
Comments
I've made very good progress getting dual support for both phpunit5 and phpunit9 - both are currently passing in travis (php 7.1 in phpunit 5, php 7.4 and 8.0 are running phpunit 9 https://travis-ci.com/github/silverstripe/silverstripe-framework/builds/233625826 - this is using a custom .travis file and also some forks of assets and the like that have compatibility commits The core of this solution is to have 2 separate versions of SapphireTest (and other classes such as FunctionalTest) within the same SaphireTest.php file on the I believe that we MUST use this solution as there's a requirement to support both phpunit 5 (not compatible with php8) AND phpunit 9 (not compatible with php7.1 or php7.2). This means that we cannot have something like a new class called SapphireTestNine, because all core unit tests extends SapphireTest. The phpunit 9 API change will be a breaking change for projects, even if they're running 7.4. This will prevent then from seamlessly running phpunit5 and phpunit9 have different API, the main things being:
There's no way around the fact that we need to update all the core unit tests in some capacity. The can be mostly achieved with a global regex find and replace, though plenty of unit tests needed some additional work. Where it made sense, I've added some forwards-compatible methods to the phpunit 5 version of SapphireTest, and some backwards compatible methods to phpunit 9 SapphireTest I've got a bunch of loose notes that will enventually form something on an upgrade guide in the description on #10028 (comment)
I think docs should be enough. The average project will be vastly simpler than core. it's likely to be just updating the return types on their
I think we should go for big bang after the 4.9 release. This doesn't mean merge every PR at once, we'd merge framework first, then do all the other modules one at a time. I'd much prefer to do this all back-to-back rather than incrementally (I'm happy to do all the work myself). This is likely to cause a fair amount of red builds in travis for a while until we fix all the loose ends. Since the bulk of the technical challenge has been solved in the framework PR, so it should be technically easy to do the rest of the core modules which are expected to be simpler than framework |
SapphireTest is a wrapper around phpunit that does a couple of things:
SapphireTest extends the phpunit class TestCase, so the vast bulk of assertions and the like is just phpunit I'm pointing this out specifically for this:
This seems like it implies we should be looking to add extra functionality to SapphireTest as part of this spike. I'd be very against doing this at this stage as what we actually want to do is just ensure that existing unit tests work on phpunit 9 with as little friction as possible. Feature development should be done separately, though I don't even think we should look to 'enhance' SapphireTest as it's just a wrapper. PHPunit 9 is the enhancement. |
Most modules have the following for require-dev:
This is going to cause composer conflicts with Recommend we take the existing silverstripe/recipe-testing which is
And make the following changes:
"silverstripe/php-testing" ^1
"silverstripe/php-testing" ^2
"silverstripe/behat-testing" ^2
Modules:Add the following to all modules require-dev so they work on any version of php 7.1 to 8+
Projects:Projects are going to vary depending on how long ago there were setup. If using installer https://github.com/silverstripe/silverstripe-installer/blob/4.3/composer.json
https://github.com/silverstripe/silverstripe-installer/blob/4.5/composer.json
https://github.com/silverstripe/silverstripe-installer/blob/4.8/composer.json
These will all continue to work with the dual versions of SapphireTest while they're on php 7. When they upgrade to php8, we'll need to make it clear for them to change to Note: Unlike We probably shouldn't recommend they use "silverstripe/php-testing" since that's more intended for internal module use, not project use, and we want the flexibility to change this at will later. |
I had high level overview. Valiant effort in trying to keep both PHPUnit 5.7 and PHPUnit 9 support. However, I suspect we might have reach an impasse where we force people to upgrade to PHPUnit 9 and break some APIs along the way. Maybe there's a way we can split the If that's not possible, I think we need to seriously look at breaking SEMVER here and drop support for PHP 7.1 and 7.2. |
Correct, the impasse is upgrading to php8, which developers do understand is a potentially breaking change to their both their code and some requirements
I'm not sure this would achieve what we want it to? Presumably we'd have a requirement in framework of
It doesn't make a difference? Let's say we did this and we release phpunit 9 version of SapphireTest in framework 4.10. Well if my site is on php7.4 when I run Again, the correct time to break the tests is during a sites upgrade to php8, and not merely |
PHP 7.4 is about to enter limited support at the end of this year. It will be EOL by the end of 2022. In this context, I find it very painful to have weird bifurcated logic in Framework to give people an extra year to consider their PHP8 upgrade. I would rather we rip the band aid off and be done with it. If we want to give people more time to make the transition, then maybe we guarantee support for the 4.9.0 branch until PHP 7.4 is EOL. There's precedent for doing this as well with our previous major releases of GraphQL and the asset permalink work. This would actually fit nicely with our GraphQL v4 release. 4.10 could be the first release where we transition to GraphQL v4 and PHPUnit 9. The 4.9 release line would be the last release to support both GraphQL 3, PHPUnit 5.7 and PHP 7.1-7.3. Which ever way we do this, I suspect the 4.9 to 4.10 upgrade won't be straightforward and people will minimally have to fiddle with their composer file. silverstripe/devIf we don't want people to accidentally upgrade to There might be some value in splitting off |
We'll, we haven't actually released this yet so we don't know what the fallout from this will be Probably not that bad because most end users won't notice the change in graphql, only those who actually have a custom graphql endpoint which is probably a fairly small number. Majority of sites will just be using graphql for asset-admin and it won't need to do any code changes. For a small number of sites though this will be a breaking change, though there is a relatively easy fix of just specify ^3 for graphql. If anything the precedent for graphql is what I'm proposing we do here, which is dual version support, as messy as it is.
Was that to do with the hash being introduced in the url on the public asset store? Yeah that was not a good experience. That was a change got reversed in 4.4 cos it broke peoples sites if I remember correctly?
So force people to upgrade to php8 if they want framework 4.10? That seems like we're just adding in a hurdle to upgrade and adding significant maintenance headache to ourselves What happens if there's a security patch we release that requires an API addition? We break semver on the 4.9 branch? This seems particularly nasty when we're up to say version 4.13 and we need to backport something to that old 4.9 version we still need to support. This is very nasty IMO. We're effectively making 4.9 the end of the road for php7.
Would need to validate this, though I think because it's a dev requirement it'll behave differently. Dev requirements of required modules aren't considered when doing a Even if dev requirements are considered specifically for I've provided a solution here which will result in minimal breakages on peoples sites. I don't really think that a solution that either breaks peoples sites or just prevents them from upgrading is going to get much community acceptance. |
SS4.0 shipped with GraphQL v1. We're not supporting GraphQL v1 and v2 anymore. Part of the rational there was that a library we relied on for our graphQL support wouldn't work with the latest version of PHP. Which is exactly the situation we're in now.
We didn't do that lightly. But there was a fundamental design flaw in assets that couldn't be remedied easily without some upgrade pains.
I'd say 4.10 can support PHP7.4 and up ... with soft support for PHP 7.3 if you don't care about unit test. PHP7.3 has been EOL for some time now, so it shouldn't be such a shocking surprise we're dropping support for it.
Adding an API to in a patch release is not great, but sometimes it's necessary to fix a security issue and we've done it in the past.
The solution you got there involves a lot of bifurcated logic which we'll be stuck maintaining for a while. We've already been maintaining some weird fork of PHPUnit for some time now ... which we should never have done. I think we are at a stage where we need to have a clean break. We're not hanging out devs to dry if we give them support an extra year to make the transition. We try our best to support third party libraries and PHP versions for as long as possible, but sometimes there's factors out of our control that makes that impossible. At some point, we just need to be honest with the community and explain that it's not practical for us to indefinitely maintain old APIs we are inheriting from third party dependencies. |
Yeah but you realise that means we essentially have 2 active minor versions, instead of 1? 4.9 would end up sticking around as "supported" for ages along with the actual current minor. We would be increasing our maintainence burden by doing this. This I do not agree with at all.
This is not really a problem in practical terms though? SapphireTest doesn't exactly get a lot of work done it - https://github.com/silverstripe/silverstripe-framework/commits/4/src/Dev/SapphireTest.php I'd estimate the ongoing "maintainence" work here to be near zero. Unlike GraphQL, SapphireTest is not in active development. After all SapphireTest is just a Silverstripe wrapper around PHPUnit to get things like fixtures working Bulk of the work here is updating all the unit tests to work with phpunit9, which I've already made large inroads into The downside to this approach seems to be "more work for CMS squad", however I estimate this extra work to be very low, so it's not really a downside? Alternative approach you're suggesting here has multiple downsides, including more ongoing maintenance, more than just having dual support. |
I've summarised a few approaches below. I'm obviously biased to the solution I presented in the POC PR's linked above, though I really do think it's the only viable solution as the other approaches are going to cause users an bad upgrade experience where either things break or they can't upgrade. Background
OptionsA. Two different versions SapphireTest/FunctionalTest in the framework codebase supported phpunit5 and phpunit9 respectively. Use the correct version depending on the version of phpunit installed**Pros:
Cons:
Notes:
B. Make php7.3 the minimum required for 4.10 - Make a semver breaking change and only include the phpunit9 SapphireTest/FunctionalTest in the codebase.Pros:
Cons:
C. Make php8 the minimum required for 4.10 - Make a semver breaking change and only include the phpunit9 SapphireTest/FunctionalTest in the codebase.Pros:
Cons:
|
Option A
Option BPHP 7.3 is already EOL, I would set the minimum to PHP 7.4. I would combine this with an extra year of support for Silverstripe CMS 4.9
In effect, this gives you a year to:
I think this is better because it gives clear guidance and timeframes for projects to move off deprecated dependencies. Option C
|
(Option A)
Ah, that's not what we're doing 😆 we have duplicate SapphireTest + FunctionalTest classes only, not unit tests. The PRs listed above upgrades the supported module unit tests themselves to work with phpunit9 and still work with phpunit5 (Option B) This really means that we're making 4.10 a quasi-major release At this point I'd just call it 5.0 |
When I did my initial review, I missed the part where we add a bunch of polyfills to restore API that PHPUnit has deprecated. I would like some clarity about how we want to approach this. Copying deprecated APIs from PHPUnit into our own codebase and adding them to our own API would be a terrible mistake. We already have a gigantic API surface to maintain. The last thing we should be doing is taking over APIs that the PHPUnit maintainer doesn't want to look after. Alternatively, we could backport some of the newer APIs back to the On a related note, the PHPUnit support timeline seems to indicate that they release a new major in February of most years. We should expect a PHPUnit10 in Feb 2022. Looking at their master branch looks like it will drop support for PHP7 altogether. We probably need to decide now what we want to do PHPUnit10. This means potentially supporting 3 different versions of PHPUnit simultaneously. Or we skip PHPUnit10 altogether and we have this entire discussion again in a year or two when PHPUnit 9 support gets deprecated. |
Looking at my previous notes on #10028 - it's basically to prevent having to rewrite large chunks of core unit tests which need to work in BOTH phpunit5 and phpunit9. Yes we could update them to work with straight phpunit9 functions, but we'd need to update a lot of unit tests (possibly not that bad, maybe find and replace will be good enough. And then we'd also need to add the forward compatibility polyfills to phpunit5) Searching in kitchen-sink for
The backwards compatibility polyfills also make it easier for existing projects to keep their unit tests as is for when they need to migrate to phpunit9. You could argue this is just being overly nice since they will have to do some work e.g. migrate off the docblocks for expected exceptions
It's probably worth re-exploring some 'find and replace' to migrate everything to phpunit9 to see if it's a semi-quick win, though it's certainly more work and I don't see backwards compatibility polyfills as really that bad maintainence wise (and obviously they're way better migration wise). I wouldn't automatically assume doing a bunch of extra work "would be less bad", particularly when there's an opportunity cost associated with doing work.
Notes copied from previous comment: assertInternalType() and assertNotInternalType() were removed - upgrade guide - sebastianbergmann/phpunit#3368 - though I've added backwards compatible versions - we've added a backwards compatible version of assertInternalType() to SapphireTest to support existing core unit tests on phpunit5, but not for assertNotInternalType() which wasn't used in any core tests assertArraySubset() has been removed. It can be polyfiled for backwards compatibility on individual SapphireTest classes with a trait in a module: composer require --dev dms/phpunit-arraysubset-asserts
phpunit10 |
If we do that, we're functionally taking over the deprecated APIs from PHPUnit and committing to supporting them. There's probably some other deprecated PHPUnit APIs that we're not using that some people out there might be using. I would rather take the extra time needed to convert all our test coverage to the PHPUnit9 equivalent and then fully drop PHPUnit5 in Dec 2022.
The "world did not end when we didn't support phpunit 6, 7 and 8" because we kept jumping through hoops to keep our PHPUnit fork working. I would rather avoid being in this position going forward. "Much later" is probably going to be Feb 2022 so it's not that far away. My guess is that PHPUnit 9 will go in limited support when PHPUnit 10 is release. I'm fine with taking the risk of "maybe not supporting PHPUnit 10" if we don't think that's essential. But if we think PHPUnit 10 is going to be essential, then the decision we make here could have lot of downstream effects and we should try to figure out what those will be. |
Max pointed out https://github.com/Yoast/PHPUnit-Polyfills Idea would be to add all the traits to the phpunit5 version of sapphiretest and remove my forwards compat polyfills. We could probably also add wrapper functions in phpunit5 sapphire test with deprecation notices and just call parent::func(). that would help during project/module migration to identify which functions needs to be changed |
We'll spin up the controller policy bit in a separate PR. |
Chiming in here to challenge "probably a non-issue". I was doing some maintenance and bumped a couple of modules up a minor version and suddenly found myself running bleeding edge, non-stable versions of SilverStripe core modules. I caught the problem in two modules, but from the looks of this thread it's bigger than that. |
Hey @davejtoews - could you check your
silverstripe/framework 4.10.0 hasn't yet been released, so the new Let me know if this isn't behaving as expected |
@emteknetnz I have exactly those settings for |
@davejtoews Sorry about this happening. We've written an explanation of what went wrong and why here. We recommend setting |
Overview
Creating this spike to investigate the approach for adopting PHPUnit 9. This is currently the main blocker for full PHP 8 support.
Update: Then do all the work :-)
Tasks
Timebox: 10 days (including consultation)
Notes
See the related issues:
PRs
Remove dms polyfill
Rerun after removing polyfills above
Rerun after polyfill removed
Archive controller policy
The text was updated successfully, but these errors were encountered: