-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Add support for Rails 6 built-in Parallel Testing #2104
Comments
We'd love to support parallel tests with RSpec itself, its a rather large task however. If we get parallelisation support into rspec-core you can be sure we'll integrate with the rails helpers. |
Note that linked #1254 says:
I believe the parallel testing now built into Rails can be process-based or thread-based, and by default is process-based. Is supporting Rails process-based parallel testing less of a challenge? It looks like one of the main things Rails does for you when supporting this is setting up a separate database for each test worker, as well as orchestrate getting each worker to run different tests and aggregating the results. |
In the short term all we could offer is to help integrate 3rd party parallel testing with Rails tools. Our own parallel journey requires changes to rspec-core which are mostly identical for process or thread based. Please note there are parallel testing extensions for RSpec already! |
Discourse now has a solution based on parallel_tests discourse/discourse#7778 |
Is there any update on supporting the activesupport |
Sorry, I meant to include a link with more details: |
No, RSpec itself needs to support parallelisation in order for it to supported |
Sorry @JonRowe - can I please clarify something? rspec-core needs updating even for multi-process parallelisation, right? (not just multi-threaded parallelisation as described in rspec/rspec-core#1254, which I would assume is more challenging) |
The main rspec-core runner doesn't support parallelisation, so it has no means of collating results from workers, be they threads or processes. Process based parallelisation is simpler than thread based due to well, the GIL on MRI rubies and lack of 100% thread safety within the other gems. (I'm fairly certain for example that there are threaded bugs lurking within the mocks code). My ideal plan for taking us to parallelisation is to use the "fork" model that the bisect runner uses, maybe with a fall back to a "shell" model (essentially processes) but I haven't had the time to work much on it. |
to summarize: regardless if thread or processes: rspec-core isn't supporting it yet, so if we run a rails 6.0 application and use rspec, we won't benefit from it. correct? |
The helpers are there to support parallelisation, rspec on its own doesn't support parallelisation so you'll need an extension gem to benefit from it. |
@JonRowe Would you copy all |
No I'm writing it from first principles using the bisect runner as a guide and some other external gems. |
@JonRowe thanks for taking this on! Is there anything we can do to help this along? Not sure I'm qualified to write any of the runner but if there's something, please let us know! |
Hey guys! What's the latest on this? |
Still awaiting finishing the core work |
Since Support Multithread Execution ticket on
All or most of those tools allow for parallelized execution in processes, arranging work with several databases via more or less common With such a variety of tools, it seems that parallel testing of Rails applications with RSpec is not really an unsolved problem. Basing on the efforts that had to be spent on building and maintaining such a tool while working full-time, I wouldn't really expect that a comparable tool to appear out of thin air in RSpec distribution and to immediately become better than everything else on the market. |
this will be awesome with rails 6+ |
@pirj I recently attempted to improve our CI testing using some of the tools you mentioned above, and I didn't have much luck. I didn't test all of them, but I did test the ones that were the most popular, and none really seemed to meet what we're looking for. In an ideal world, a solution for this would do the following:
My understanding of the Rails feature is that it gets us more of the way there. This still feels like an unsolved problem to me for Rspec. I believe Jest does something like this at the file level in JavaScript. It would be awesome to see. |
@LandonSchropp I have bad news for you if you really need to aggregate the results into a single standard RSpec report. It's a hard task with a number of non-obvious edge cases. We've solved it on my previous project, at least for those cases that we've faced. The report is gathered from different workers, spread over different processes or even machines. Unfortunately, it's not open-sourced yet. As to my memory, we had no big issues with aggregating SimpleCov results, but that worked before I joined and I didn't work on this part. Auto-scaling to multiple available cores is a trivial task. Once you (depending on your system flavour and CPU type) get the number of processors, you're able to run Another non-trivial task is to evenly distribute your specs across those parallel processes. If you don't, you risk that one of the processes will be running for a significant amount of time, while other cores will finish already and will be idle. It is solved in Knapsack Pro and AFAIR in rrrspec.
Honestly, I'm not so sure about that. A major flaw I could spot is that Rails doesn't detect if a worker died and did not finish all the workload it was supposed to execute. A better way is to have a timeout and consider worker as dead and spread over its remaining workload among alive workers. This is also solved in my previous project. |
@pirj Thanks for the detailed reply! Sorry if my post sounded like I was trivializing the amount of work involved in this. That definitely wasn't my intention. My goal in my last message was more to enumerate my team's use case in the hopes that it could influence the future design of this feature. I'm sure that a refactor along these lines is a massive undertaking.
I'll have to take a second look at that. When I was investigating, it wasn't clear to me how I'd go about that. I found one plugin for integrating SimpleCov with parallel-tests, but it said it was only compatible with CircleCI, and we're using Codeship, so I didn't explore it further. If you have any hints you could share, I'd appreciate it.
Yep, that's what we're currently doing. In my laptop, I've got 8 cores, each with hyperthreading, so that spins up 15 processes to run on. With that many simultaneous tests running, you can see how managing output would be helpful. I hadn't looked into aggregating JUnit XML compatible results. Do you have an example of something like that with Rspec you could point me to? Maybe that would help solve some of our problems. Our CI processes have four cores available, so it's somewhat less of a concern there.
That's roughly my experience as well. We have a few specs in our application are that are slower than others, but for the most part the costs of individual specs are amortized over our files. Based on my observations of using Jest, it looks like it breaks the spec files into a queue, and then runs each file as a worker becomes available. In our use case, pre-splitting the specs has worked fine. When I was exploring Knapsack, I actually felt like it was trying to solve a different problem than what we were experiencing. As you said, for us, it was less about distribution and more about taking advantage of multiple cores locally and in our CI environment.
I can't speak to that. I'm sure you're absolutely correct, and I agree with you that the behavior you're describing sounds better than what's being done by the Rails runner. What I meant more from my comment is that what's advertised from the Rails runner is more what we're after. It advertises that it automatically detects the number of cores on the machine, creates the test databases for us, and then splits up our tests and runs them. We love Rspec and will continue to use it over Minitest, but it would be awesome if there were an analog to the parallel features with Rspec that was as easy to use as the Rails solution. Thanks again for your detailed reply. I really appreciate it! |
I can't speak to the rest of it, but as for merging JUnit reports, I've done that before in a different context. The file format is pretty simple, it would just be a matter of a little Nokogiri code to open each report and output a bigger report with the contents of each. Just have each rspec process output in JUnit format and then handle the aggregation and printing of results yourself |
@JonRowe Discourse would be happy to fund some work here if you or any other contributors are looking to build it. Some requirements from me :)
If anyone want to work on this and would like the work funded, DM me via Twitter. @SamSaffron |
My plan is to build support for parallelism into rspec-core, which solves many of the problems with plug'n'play, both as our own option, and the ability to farm work out to other plugins. Fork is absolutely on those planes. I very much like the idea of the master rspec process controlling the queue like that, as it allows much easier non interleaved output, which was very much essential. From there I hadn't thought about the possibility of such a model being a long running process, and reloading / rerunning specs, thats got a set of complications all on its own (as I'm sure you know!) |
@JonRowe it must be noted too that parallelism in Rspec will also give a strong acceleration to all the "TDD devops" tools which happen to be based on RSpec (like InSpec and ServerSpec). Just a side-dish, but a very nice one, and definitely useful to the reputation of Ruby as a whole ^_^. Given that, maybe Chef could also be willing to provide some funding in that area (I'm not working there, but just making a wild guess!). |
@JonRowe @SamSaffron My company, CommitChange, would be able to add a small amount to the parallel testing pot. It'd be well under $1000 (we just don't have the resources to spend a lot more) but it's something if it'd help. I totally get if this isn't enough to bother but there's likely many smaller users who might be able to put in a few hundred. |
thanks everyone, I have been chatting privately to @JonRowe and it looks like Jon may have some time for this project, stay tuned 🎊 |
No promises. This depends on contributors mostly. RSpec core team has limited resources and is working on releasing support for Rails 7, trying to get RSpec 4 out of the door, and a number of housekeeping tasks. I encourage you to take a stab at it, and report how far you went through, what went wrong. We can adjust RSpec Core/Mocks as needed to support in-process concurrency. |
I think where this was left off is that the result of "take a stab at it" is https://github.com/ioquatix/turbo_test/, and so next steps for anyone who wants parallel test support (me included :) ) is to implement that gem and report any issues. Is that right? If turbo_test gets enough adoption and validation, would that approach then be folded into rspec? |
Checking Rails testing guide:
Process forking approach has been available for running RSpec in parallel in the local development for a long time already. Check #2104 (comment) for a list. There are numerous blog posts how to set it up, including for Rails. This shifts the "inherent deficiency, obviously a downside" argument into "is not available out of the box, needs additional setup". And, from my perspective, shifts its priority a bit down. Should we embrace and absorb, bundle or reinvent one of those tools? Should we work on supporting in-process concurrency (threads, fibers, ractors, ... whatever comes next)? Should we give our preference and advertise one of the tools in our documentation, optionally provide it as part of our I would be happy to see a streamlined approach, but it's unlikely to happen without outstanding contributors' dedication to develop and spread the word. The tool should really stand out, as the currently existing ones work in most cases, too. |
@griou We run our rspec/capybara test suite using https://github.com/grosser/parallel_tests It works well, you just have to make some different config adjustments for things that run outside of rails during the test suite run, i.e. capybara ports, database selection (per process), elasticsearch indices (per process), redis, etc... See the wiki for examples https://github.com/grosser/parallel_tests/wiki |
@pirj I think I have to add another perspective here. Been around Rails projects since 2.3 was latest and greatest. Up until now for every new project we went with RSpec. But now starting on a new project there is really big incentive to switch - it's included out of the box, automatic and will be supported. So it is not only missing feature, but becoming kind of branding issue. In-process concurrency would be great, but maybe first step is to just provide up to date list of existing tool and provide some options in install template. The template option might be bridge to other tool owners to iron out some integration issues and simply drive interest to them. |
https://github.com/serpapi/turbo_tests author here. Shameless plug, but it's available as a gem and works as a replacement for the PS. All I did is copy-pasted part of the source code from Rubygems and Discourse, adjusted it a bit, and packaged it into a gem (#2104 (comment)). |
FWIW, https://github.com/serpapi/turbo_tests worked out of the box (added gem, ran By contrast, https://github.com/ioquatix/turbo_test required a bunch of setup steps (ioquatix/turbo_test#6) and is now throwing an error when I try it again. |
MIT vs GPLv2 😱 Worked perfectly fine as a drop-in replacement/wrapper for Before:
After:
What was missing (and what Rails provides with its default testing framework):
Without Spreading out tests evenly, dynamically (with a queue), and considering individual specs' CPU/IO ratio is out of comparison and is on par with Rails. |
Same! Been following this thread since 2019 and this week it paid off—thanks @ilyazub! |
@bmulholland @pirj @jkeen Thanks for your kind words!
I guess I can change the license from MIT to GPLv2 and add copyright headers if needed. I've used the MIT license because that's what
Yes, @pirj Thank you for mentioning the automatic DB creation in Rails. I've opened an issue in the Btw, |
Most likely you have to use GPLv2. Only users of your gem might have some problem if they don't check the license is GPLv2. |
Only if they decide to supply a modified version of The Rails community incident is the reason why I mention GPL vs MIT above:
|
Happy for the code that was extracted from discourse to be treated as MIT!
…On Sat, 29 Jan 2022 at 7:21 pm, Phil Pirozhkov ***@***.***> wrote:
users of your gem might have some problem if they don't check the license
is GPLv2
Only if they decide to supply a modified version of turbo_tests as an
integral part of their proprietary software to another party. To my best
knowledge, GPL does not apply any restrictions on using GPL-licensed
software for CI or local development, commercial or otherwise, modified or
not.
The Rails community incident
<mimemagicrb/mimemagic#97 (comment)> is
the reason why I mention GPL vs MIT above
<#2104 (comment)>
:
GPL header removed.
The license that you're shipping mimemagic under (MIT) isn't compatible
with shared-mime-info's.
—
Reply to this email directly, view it on GitHub
<#2104 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAABIXNRHDZZYR7UTKL6KHLUYOPQHANCNFSM4HCVUOKQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Thanks a lot, @SamSaffron ! ❤️ @ilyazub I suppose you can consider this written permission to use parts of GPL-licensed Discourse code in your MIT-licensed
|
Great discussion, I'm really excited to see people passionate about testing! Just reading through some of the comments here, it seems like we need a better model for parallel testing. From what I see, I think Regarding parallelism, I think there are enough issues in Rails test harness that some improvements there would be useful: better handling of To this end, I decided to try implementing a green-field parallel test runner and ended up with https://github.com/ioquatix/sus which I'm now using in a handful of projects. It's designed from the ground up for multi-thread parallelism by ensuring all tests can be run in total isolation (i.e. the semantic model is built from the ground up for isolation). Interestingly enough, I've been toying with an idea to host other test frameworks within Maybe After playing around in this space for a while, I think what we want is this:
|
Shelling out on MRI is not that bad. Did a quick test in our project with
vs
|
@Unknown-Guy Yes, a one-minute speed-up could be better. How many |
@ilyazub there's 277 files there, 4425 examples Edit: think the startup is what eats the time here, shelling out and starting another jruby process is very expensive. Maybe this could work together with something like Theine. Just wanted to add that that the approach with shelling out has pretty big drawback on jRuby. |
Looks like a new tool for rspec parallel testing https://github.com/briandunn/flatware |
@ryanong Thank you for suggesting it! It uses Unfortunately, it's slower than
Tested with Ruby 2.7.2 on 8 core i7-6700HQ CPU @ 2.60GHz.
There're 196 spec files (2,1K examples) in the directory I've used to compare the speed.
P.S. Maybe it's possible to parallel execution of examples instead of spec files using |
For me, |
Not very rigorous, but FWIW on my M1 MBP (8-core, 32GB), running our Rails project's 4260 examples across 526 spec files:
I ran each a handful of times and reported the best time (which is admittedly unfairly biased in favour of parallel_tests, which would often have by far the worst of the parallel runners' times due to poorly balanced specs) flatware does seem consistently faster for me, although it has a few rough edges with things like not being able to interrupt the tests with ctrl-c, the extra complications of a flatware-sink background process, and an unexplained single test failure I haven't figured out the cause of yet. |
@jdelStrother Just released a new version - would love to address these concerns could you open an issue? |
@briandunn seems pretty good now! It behaves properly with ctrl-c, and I don't seem to be seeing the random test failure from last time I tried. |
My concern is, that with all the tools one need to execute a different command than |
Use Rails 6 built-in parallelizer API for running parallel RSpec executors
https://edgeguides.rubyonrails.org/testing.html#parallel-testing
rails/rails#31900 (comment)
The text was updated successfully, but these errors were encountered: