-
Notifications
You must be signed in to change notification settings - Fork 524
chore(dashboard/tests): ensure any DB changes are rolled back #70189
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors the transactional test case implementation to ensure database changes are automatically rolled back after tests. The key change is moving from an opt-in use_transactional_test_case class attribute to leveraging Rails' built-in use_transactional_tests feature, which is now explicitly enabled by default in TransactionalTestCase.
Key Changes:
- Simplified
TransactionalTestCasemodule to use Rails' built-in transactional test support - Modified
setup_allto wrap its block in a database transaction that's rolled back inteardown_all - Removed all manual
self.use_transactional_test_caseassignments across the codebase since transactional behavior is now enabled by default
Reviewed changes
Copilot reviewed 121 out of 121 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| dashboard/test/testing/transactional_test_case.rb | Core refactoring: simplified to use Rails' use_transactional_tests and wrapped setup_all blocks in transactions |
| dashboard/test/testing/test_case_test.rb | Added test coverage for the new transaction behavior in setup_all |
| dashboard/test/models/*.rb (45 files) | Removed redundant use_transactional_test_case assignments |
| dashboard/test/lib/*.rb (21 files) | Removed redundant use_transactional_test_case assignments |
| dashboard/test/controllers/*.rb (43 files) | Removed redundant use_transactional_test_case assignments |
| dashboard/test/integration/*.rb (3 files) | Removed redundant use_transactional_test_case assignments |
| dashboard/test/helpers/*.rb (2 files) | Removed redundant use_transactional_test_case assignments |
| dashboard/test/models/pd/application/principal_approval_application_test.rb | Changed setup_all to setup (no longer needs transaction wrapping) |
| dashboard/test/lib/services/complete_application_reminder_test.rb | Changed setup_all to setup (no longer needs transaction wrapping) |
| dashboard/test/lib/pd/survey_pipeline/mapper_test.rb | Changed setup_all to setup (data setup doesn't require persistence) |
| dashboard/test/lib/pd/survey_pipeline/daily_survey_joiner_test.rb | Changed setup_all to setup (data setup doesn't require persistence) |
| dashboard/test/controllers/api/v1/pd/teacher_attendance_report_controller_test.rb | Consolidated setup_all time travel into setup block |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| setup_all do | ||
| if use_transactional_test_case? | ||
| setup_fixtures |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
this could be worth trying, but I am concerned that if you want to continue down this path, my recommendation would be to do a similar test to the commit linked above, as proof that we are cleaning up between tests. because we run tests 7 ways parallel in drone, I would recommend adding the colliding objects to at least 10 different setup_all blocks. |
use_transactional_tests opens a transaction for each test case (the So code-dot-org/dashboard/test/testing/transactional_test_case.rb Lines 30 to 38 in 3f113e3
But we still need to cover this one: code-dot-org/dashboard/test/testing/transactional_test_case.rb Lines 18 to 27 in 3f113e3
|
This does not really matter, since parallel tests run across isolated worker processes with separate test databases while still executing tests sequentially within each worker |
that may be, but the number of separate test databases is also 7. if you add 7 colliding objects to fewer than 7 setup_all methods, then you run the risk that each one pollutes exactly one test db without ever having a collision. |
The existing TransactionTest already verifies database isolation by establishing a baseline, making a change in one test, and then confirming in a subsequent test that the change was rolled back, but I can add more tests if needed. |
davidsbailey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for following up on this Artem! It looks promising, but I think some explicit manual validation is needed to prove that this does the right thing. The following seems like it would be adequate to me:
- introduce some colliding object names, as illustrated in previously linked commit
- do some print debugging to prove that when running a single test file, the setup_all method in the test file is being executed after the database transaction
| # Setting this to true causes some weird db locking issue, possibly due to | ||
| # some writes to the projects table coming from a different connection via | ||
| # sequel. | ||
| self.use_transactional_test_case = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please keep a version of the comment explaining that any new failures due to db locking issues could be due to the reason described here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let me know if this warning is fine, or if you would prefer to keep the original comment:
code-dot-org/dashboard/test/testing/transactional_test_case.rb
Lines 21 to 24 in 2788061
| # Ensures any database changes made in setup_all are rolled back after all tests in the class. | |
| # @warning This keeps a transaction open for the whole test class. | |
| # Writes from other connections, for example Sequel, can wait on locks or hit a MySQL deadlock. | |
| private def setup_all(*args, &block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is not much in this setup_all block. how about consolidating it into the setup block instead? then the existing comment should be fine, since that should eliminate the known risk in this particular file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that link didn't work for me, but the updated contents of CodeReviewsControllerTest looks good to me!
sorry I missed this earlier comment. I don't see anything in that test which covers the case where the colliding objects are created in setup_all, so it seems like this is covering the |
7dad9f6 to
ca3db3c
Compare
ca3db3c to
2420186
Compare
Added some tests: 77994c4 |
… tests feature with custom transaction wrapper
…nSummaryPodcastsControllerTest
…tion query created by lazy transaction
f27c5ab to
3c463e6
Compare
| class ActiveSupport::Testing::TransactionalTestCaseTest < ActiveSupport::TestCase | ||
| UNIT_NAMES = Array.new(10) {Faker::Lorem.unique.word.downcase} | ||
|
|
||
| setup_all do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like one of my comments is not showing up on the PR. Please double check that this call to setup_all runs when you expect it to, because it can sometimes have unexpected behavior when run with describe / it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already verify that the data and instance variables created in the root class setup_all callback are shared in the describe/context/it blocks, which is expected and desirable behavior. And that they run within a single transaction, meaning no extra transaction is created. Could you please specify what else you would like us to verify?
Wraps
setup_allcallbacks in a class-level DB transaction (rolled back inteardown_all) so records created insetup_allcannot leak across tests, without relying onuse_transactional_test_caseLinks