Improve validation of openedx_content to prevent creation of corrupt states#521
Improve validation of openedx_content to prevent creation of corrupt states#521bradenmacdonald merged 7 commits intomainfrom
Conversation
|
Thanks for the pull request, @bradenmacdonald! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
5c69fc1 to
dda0024
Compare
34a6794 to
03237af
Compare
…idation Co-Authored-By: Claude <noreply@anthropic.com>
03237af to
c689d0a
Compare
| def test_reset_drafts_to_published_bulk(self) -> None: | ||
| """bulk_draft_changes_for creates only one DraftChangeLog.""" | ||
| with publishing_api.bulk_draft_changes_for(self.learning_package_1.id): | ||
| self.test_reset_drafts_to_published() | ||
| assert DraftChangeLog.objects.count() == 1 |
There was a problem hiding this comment.
Since it's hard to tell from the diff what's going on here:
This test_reset_drafts_to_published_bulk just called test_reset_drafts_to_published() inside bulk_draft_changes_for but that inner test does some setup, a publish, more setup, then a revert, so this was causing an error - we don't want to allow publishes inside bulk_draft_changes_for.
The refactored test is almost exactly the same, but is parametrized and when bulk=True it wraps the pre-publish setup in a bulk transaction, and the post-publish setup+revert in a second bulk transaction.
I think this is an even better test now because we can assert that the net effect of the second bulk transaction is zero, as it reverts to the published version.
My local git client shows the diff more cleanly than GitHub:

c689d0a to
1abbf1e
Compare
ormsbee
left a comment
There was a problem hiding this comment.
Minor request on more detail in the errors being raised.
|
|
||
| from django.contrib.auth import get_user_model | ||
| from django.core.exceptions import ObjectDoesNotExist | ||
| from django.core.exceptions import ObjectDoesNotExist, ValidationError |
There was a problem hiding this comment.
[Comment]: I've generally used ValueError instead of ValidationError for invalid arguments, though I realize that doesn't make sense for things like checking that you're not in a bulk change context before publishing. Should I switch over, do you think?
There was a problem hiding this comment.
For these errors that are more developer-facing (you coded something wrong, not the user gave invalid input), I honestly don't think it makes much difference. I'm on the fence and happy to change to ValueError too if you'd like.
The python docs say
ValueError: Raised when an operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception
So I guess it depends if you consider ValidationError to be more precise. We could also define a custom exception that's even more specific, but I don't think it's worth it if we expect these to be pretty rare.
|
@ormsbee I added in that extra logging you requested. |
|
@bradenmacdonald, @kdmccormick: Just a heads up that something here is causing test failures in the modulestore migrator code. |
This PR implements tests for four of the issues identified in #463 .
set_draft_version()should reject aPublishableEntityVersionthat belongs to a differentPublishableEntity.publish_from_drafts()should reject drafts that don't belong to the specifiedLearningPackage.create_publishable_entity_version()should rejectdependenciesthat are from a differentLearningPackage.publish_all_drafts()andpublish_from_drafts()should not be callable from within abulk_draft_changes_for()context.Another issue is in a separate PR for simplicity: #569
Two issues are unaddressed as they are API design choices:
create_publishable_entity_version()andcreate_publishable_entity()can both create either a useless or an invalid state if they are used on their own without corresponding [Component/Container/etc.] versions.Platform: no corresponding changes are required in openedx-platform as far as I can tell.