Closed symbioquine closed 3 years ago
Tests take a really long time
Agreed - and part of this may be due to the fact that XDebug is installed in the dev image, which is also used for running tests currently. We need to change this. It was just a result of the way I set up the Docker containers and testing instructions originally, and now that our tests are growing it's becoming a problem. That said, I'm not exactly sure how much of an impact it's having, and/or if there are other optimization options.
Everything else you describe is outside the scope of farmOS/Drupal I think, however. We are basically just running phpunit
in the recommended way. But I'd certainly love to see some improvements! All of the points you make are valid! This might need to be explored upstream.
Here is where the PHPUnit configuration is set up in our Dockerfile currently: https://github.com/farmOS/farmOS/blob/2ce6c8eac09540ba683a910da37285e5d7e6d3b4/docker/dev/Dockerfile#L56
You may have noticed, but we also have a GitHub Action for building the Docker images from scratch and running the tests: https://github.com/farmOS/farmOS/blob/2.x/.github/workflows/run-tests.yml
This seems to take ~20 minutes on average to run right now. That includes building the images. Tests themselves run in ~15 minutes on GitHub's servers: https://github.com/farmOS/farmOS/actions?query=workflow%3A%22Run+2.x+PHPUnit+tests%22
FWIW the SIMPLETEST_DB="pgsql://farm:farm@pgsql/farm" -e SIMPLETEST_BASE_URL="https://v2.farmos.test"
parameters shouldn't be necessary in the command you're running. Those are set in phpunit.xml
: https://github.com/farmOS/farmOS/blob/2ce6c8eac09540ba683a910da37285e5d7e6d3b4/docker/dev/Dockerfile#L59
Notably, SIMPLETEST_BASE_URL
is set to http://localhost
. I wonder if that's what's breaking your browser tests?
All that said, I welcome suggestions from anyone who has more knowledge and experience with Druapl PHPUnit testing than I do! :-)
Thanks for taking time to respond to my rant @mstenta!
Everything else you describe is outside the scope of farmOS/Drupal I think, however. We are basically just running
phpunit
in the recommended way. But I'd certainly love to see some improvements! All of the points you make are valid! This might need to be explored upstream.
That makes sense. Exploring many of these upstream would definitely be a reasonable strategy.
I think tracking these pain points here is also worthwhile though since the farmOS project itself is also responsible for the developer experience consequences of the technology/configuration choices involved.
In addition to the idea you mentioned about experimenting with disabling xdebug, one strategy I can imagine would be to split the tests into more finely grained groups and run all the groups as separate jobs in parallel for the GitHub action. As long as we don't run into some sort of usage limit that would probably scale pretty well to larger numbers of tests at the cost of some additional complexity in the GitHub action. It might also improve the developer experience prior to check in by providing a more structured way beyond custom test filters for devs to run a smaller set of tests more frequently and only run the full set just before check in.
FWIW the
SIMPLETEST_DB="pgsql://farm:farm@pgsql/farm" -e SIMPLETEST_BASE_URL="https://v2.farmos.test"
parameters shouldn't be necessary in the command you're running.
I set those because my docker container names differ right now from the defaults and I'm running farmOS behind a reverse proxy, but I see what you mean now about how I could leave SIMPLETEST_BASE_URL
alone since the tests are running from within the same container.
In addition to the idea you mentioned about experimenting with disabling xdebug, one strategy I can imagine would be to split the tests into more finely grained groups and run all the groups as separate jobs in parallel for the GitHub action.
Oh this is a really interesting idea! How would this work? Multiple action YML files that all get triggered by the same push, but execute a different test? Or could it be done all in one YML?
We might need to think about splitting the Docker image build process out, so it's not repeated every time. I kinda like how it's an "end to end build+test" right now, but probably not the best approach in the long run.
But yea getting XDebug out of there should probably be step 1.
I think tracking these pain points here is also worthwhile though since the farmOS project itself is also responsible for the developer experience consequences of the technology/configuration choices involved.
Agreed - looking back my reply was a bit too much on the "not my problem" side of things. :-)
That may still be true generally, but I'm curious if there are optimizations we can make with our PHPUnit config as well.
Found this: https://kriswallsmith.net/post/27979797907/get-fast-an-easy-symfony2-phpunit-optimization
I wonder if Drupal core is already doing that...
How would this work? Multiple action YML files that all get triggered by the same push, but execute a different test? Or could it be done all in one YML?
It is feasible to do it in one YML file - it might even be preferable to combine the existing ones such that the docs/release actions only happen once the tests have passed...
I've created a test repository demonstrating how tests could be run in parallel in separate jobs, then feed into the docs/release steps.
From some example test runs 1, 2 we can see that each of the test cases runs in a little over 1 minute - thus demonstrating that it didn't incur the cost of the docker image build again. Also the total workflow runs in about 3 - 4 minutes - thus demonstrating that, at least for this test case, the parallelism produced a speed-up over running all test cases sequentially (presumed to take more than 5 minutes).
This is great @symbioquine ! Thanks for demonstrating!
We've been using the drupal.org issue queue for specific 2.x development tasks. I opened a new issue over there for running tests in parallel, under the "2.x build process" roadmap: https://www.drupal.org/project/farm/issues/3183682
I also created a dedicated issue for running tests without Xdebug: https://www.drupal.org/project/farm/issues/3183687
Interesting idea to combine the tests+docs+release scripts too. I'd like let that idea simmer a bit in my head - but maybe we can spin up a meta issue to think about that as well. I kind of like that they are separate and "do one thing" right now, but let's think about it!
@symbioquine I just discovered another reason why the tests are taking a long time!
TL;DR: A whole bunch of farmOS modules are being installed with every test, and they shouldn't be.
Edit: This is only an issue with functional tests (that inherit from BrowserTestBase
. Kernel and Unit tests are not affected.
This is happening because the farm
profile is being installed with many of the tests (so that the profile's modules are available to the testing environment). This should be fine, because the profile itself doesn't install many modules on its own (limited dependencies declared in farm.info.yml
). However, the profile also implements hook_install_tasks()
, which installs a set of default modules. I didn't think that would run with tests, but it does.
I stumbled across this while debugging this recent test failure: https://github.com/mstenta/farmOS/runs/1430866938
Working on a fix for it now... this should help to speed things up quite a bit too. :-)
@symbioquine very cool!
One other improvement we could do is change some of the BrowserTests to Kernel tests. Its possible to make requests and check responses without all the overhead of BrowserTest. I suppose this would be for anything that doesn't need to explicitly be tested in the browser window, like API requests or checking for the existence of text.
I used this technique recently for the data stream API tests. We should do this for the farm_api
tests too.
+1 to Kernel tests wherever possible!
Worth noting, the issue I described above ("A whole bunch of farmOS modules are being installed with every test, and they shouldn't be.") is only happening with Functional tests, not Kernel tests.
FYI I opened a new issue for that: https://www.drupal.org/project/farm/issues/3183739
A bit tricky to solve... thinking through options...
Wow thanks, this is awesome! Glad this has prompted so many avenues of investigation...
I think this issue should be tagged with the farmOS 2.x
tag also.
Interesting idea to combine the tests+docs+release scripts too. I'd like let that idea simmer a bit in my head - but maybe we can spin up a meta issue to think about that as well. I kind of like that they are separate and "do one thing" right now, but let's think about it!
Yeah, that's definitely a trade-off. One hybrid strategy could potentially be to use the repository-dispatch pattern to kick off the docs/release workflows only upon successful completion of the build/test workflows. This would have the advantage of decoupling the success of the docs/release workflows from each other and reduce the size of each YAML file.
Good to know!
Worth noting: the tests and docs workflows both run whenever the 2.x
branch is pushed. But the release workflow only runs when a 2.*
tag is pushed. So to start we can at least push 2.x, wait for the tests to pass, then tag and push a release.
The docs being built is less urgent to tie to tests, I think, because it's just running mkdocs build
and pushing it to https://2x.farmos.org
FYI I pushed a temporary (UGLY) fix for the functional tests. See comment here: https://www.drupal.org/project/farm/issues/3183739#comment-13910556
Unfortunately, that revealed that another one of our tests was implicitly depending on a module that is no longer being enabled, so now tests are failing again. :-)
Tests ran in ~8 mins with that fix (roughly cut the time in half)!
Next steps for optimization:
Tests will be pretty speedy after that!
Next steps for optimization:
- Run without XDebug
- Run in parallel
@mstenta if you haven't already started on them, I'd be happy to experiment with putting together a PR for those next steps...
I have not! Go for it! I have some thoughts regarding the xdebug one, but might help from some fresh eyes as well. If you feel confident with the parallel processing one that might have the most impact.
If you feel confident with the parallel processing one that might have the most impact.
Yeah, I'll probably start there.
I have some thoughts regarding the xdebug one, but might help from some fresh eyes as well.
My tentative plan was building a separate Docker image based on the production one similar to how the "dev" image is built in the tests currently - minus the xdebug installation step obviously. When I played around with it previously, I didn't see a good way to disable xdebug once it is installed without more complicated php configuration changes.
I posted my thoughts here: https://www.drupal.org/project/farm/issues/3183687#comment-13910778
Are there other things worth discussing or spinning off as todos? Or do you think we can close this issue?
Not that I'm aware of. I'm comfortable tracking this going forward with the Drupal.org issues.
I started to play around with the tests for farmOS 2.x with some successes. The tests which hit the database seem to be passing locally, however those which are based on web requests aren't. I'm sure there's something about my configuration which is breaking them, but I'm less concerned about that than the experience of working with the tests.
I may have been spoiled by Java, Python, and even Javascript test frameworks which tend to produce concise, informative stack traces and assertion failures.
Some frustrations here;
<Ctrl>-c
loses any failure output which might have been later printed for already run test cases - the process just endsI'm hoping there's some magic bullet or tricks that makes phpunit and the Drupal test scaffolding more sane to work with - hopefully without depending on a proprietary IDE - but at worst I guess this issue can just capture the frustration I'm experiencing :)
Examples console output;