-
Notifications
You must be signed in to change notification settings - Fork 136
Add support for adding pull-through content to associated repositories #6224
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
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Added ability for plugins to dispatch a task to add pull-through content to an associated repository. | ||
|
|
||
| Add the class var `PULL_THROUGH_SUPPORTED = True` to the plugin's repository model to enable this | ||
| feature. Plugins can also customize the dispatched task by supplying their own | ||
| `pull_through_add_content` method on their repository model. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,21 +119,27 @@ def checkpoint_publication_2(repo_version_3, noncheckpoint_publication): | |
| def test_save_artifact(c1, ra1, download_result_mock): | ||
| """Artifact needs to be created.""" | ||
| handler = Handler() | ||
| new_artifact = handler._save_artifact(download_result_mock, ra1) | ||
| content_artifacts = handler._save_artifact(download_result_mock, ra1) | ||
| c1 = Content.objects.get(pk=c1.pk) | ||
| assert new_artifact is not None | ||
| assert c1._artifacts.get().pk == new_artifact.pk | ||
| assert content_artifacts is not None | ||
| assert ra1.content_artifact.relative_path in content_artifacts | ||
| artifact = content_artifacts[ra1.content_artifact.relative_path].artifact | ||
| assert c1._artifacts.get().pk == artifact.pk | ||
|
|
||
|
|
||
| def test_save_artifact_artifact_already_exists(c2, ra1, ra2, download_result_mock): | ||
| """Artifact turns out to already exist.""" | ||
| cch = Handler() | ||
| new_artifact = cch._save_artifact(download_result_mock, ra1) | ||
| new_content_artifacts = cch._save_artifact(download_result_mock, ra1) | ||
|
|
||
| existing_artifact = cch._save_artifact(download_result_mock, ra2) | ||
| existing_content_artifacts = cch._save_artifact(download_result_mock, ra2) | ||
| c2 = Content.objects.get(pk=c2.pk) | ||
| assert existing_artifact.pk == new_artifact.pk | ||
| assert c2._artifacts.get().pk == existing_artifact.pk | ||
| assert ra1.content_artifact.relative_path in new_content_artifacts | ||
| assert ra2.content_artifact.relative_path in existing_content_artifacts | ||
| new_artifact = new_content_artifacts[ra1.content_artifact.relative_path] | ||
| existing_artifact = existing_content_artifacts[ra2.content_artifact.relative_path] | ||
| assert new_artifact.artifact.pk == existing_artifact.artifact.pk | ||
| assert c2._artifacts.get().pk == existing_artifact.artifact.pk | ||
|
|
||
|
|
||
| # Test pull through features | ||
|
|
@@ -176,9 +182,15 @@ async def create_remote_artifact(remote, ca): | |
| ) | ||
|
|
||
|
|
||
| async def create_distribution(remote): | ||
| async def create_repository(): | ||
| return await Repository.objects.acreate(name=str(uuid.uuid4())) | ||
|
|
||
|
|
||
| async def create_distribution(remote, repository=None): | ||
| name = str(uuid.uuid4()) | ||
| return await Distribution.objects.acreate(name=name, base_path=name, remote=remote) | ||
| return await Distribution.objects.acreate( | ||
| name=name, base_path=name, remote=remote, repository=repository | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
|
|
@@ -285,7 +297,8 @@ def test_pull_through_save_single_artifact_content( | |
| ra = RemoteArtifact(url=f"{remote123.url}/c123", remote=remote123, content_artifact=ca) | ||
|
|
||
| # Content is saved during handler._save_artifact | ||
| artifact = handler._save_artifact(download_result_mock, ra, request=request123) | ||
| content_artifacts = handler._save_artifact(download_result_mock, ra, request=request123) | ||
| artifact = content_artifacts[ra.content_artifact.relative_path].artifact | ||
|
|
||
| remote123.get_remote_artifact_content_type.assert_called_once_with("c123") | ||
| content_init_mock.assert_called_once_with(artifact, "c123") | ||
|
|
@@ -319,14 +332,16 @@ def content_init(art, path): | |
| ca = ContentArtifact(relative_path="c123") | ||
| ra = RemoteArtifact(url=f"{remote123.url}/c123", remote=remote123, content_artifact=ca) | ||
|
|
||
| artifact = handler._save_artifact(download_result_mock, ra, request123) | ||
|
|
||
| ca = artifact.content_memberships.first() | ||
| assert ca.content is not None | ||
| content_artifacts = handler._save_artifact(download_result_mock, ra, request123) | ||
| ca1 = content_artifacts["c123"] | ||
| ca2 = content_artifacts["c123abc"] | ||
| assert ca1.content is not None | ||
| assert ca2.content == ca1.content | ||
| assert ca1.artifact == artifact123 | ||
|
|
||
| artifacts = set(ca.content._artifacts.all()) | ||
| artifacts = set(ca1.content._artifacts.all()) | ||
| assert len(artifacts) == 2 | ||
| assert {artifact, artifact123} == artifacts | ||
| assert {ca2.artifact, artifact123} == artifacts | ||
|
|
||
|
|
||
| @pytest.mark.django_db | ||
|
|
@@ -446,3 +461,41 @@ def test_handle_checkpoint_before_first_ts( | |
| ) | ||
| with pytest.raises(PathNotResolved): | ||
| Handler._select_checkpoint_publication(checkpoint_distribution, f"{request_ts}/") | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| @pytest.mark.django_db | ||
| async def test_pull_through_repository_add(request123, monkeypatch): | ||
| """Test that repository adding is called when supported.""" | ||
| handler = Handler() | ||
| handler._stream_content_artifact = AsyncMock() | ||
|
|
||
| content = await create_content() | ||
| ca = await create_content_artifact(content) | ||
| remote = await create_remote() | ||
| await create_remote_artifact(remote, ca) | ||
| repo = await create_repository() | ||
| monkeypatch.setattr(Remote, "get_remote_artifact_content_type", Mock(return_value=Content)) | ||
| monkeypatch.setattr(Repository, "pull_through_add_content", Mock()) | ||
| distro = await create_distribution(remote, repository=repo) | ||
|
|
||
| try: | ||
| # Assert with Repository.PULL_THROUGH_SUPPORTED=False the method isn't called | ||
| await handler._match_and_stream(f"{distro.base_path}/c123", request123) | ||
| handler._stream_content_artifact.assert_called_once() | ||
| assert ca in handler._stream_content_artifact.call_args[0] | ||
| repo.pull_through_add_content.assert_not_called() | ||
|
|
||
| # Now set PULL_THROUGH_SUPPORTED=True and see the method is called with CA | ||
| monkeypatch.setattr(Repository, "PULL_THROUGH_SUPPORTED", True) | ||
| handler._stream_content_artifact.reset_mock() | ||
| await handler._match_and_stream(f"{distro.base_path}/c123", request123) | ||
| handler._stream_content_artifact.assert_called_once() | ||
| assert ca in handler._stream_content_artifact.call_args[0] | ||
| repo.pull_through_add_content.assert_called_once() | ||
| assert ca in repo.pull_through_add_content.call_args[0] | ||
| finally: | ||
| await content.adelete() | ||
| await repo.adelete() | ||
| await remote.adelete() | ||
| await distro.adelete() | ||
|
Comment on lines
+497
to
+501
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need that... Django unittests usually run in a transaction that never gets committed. |
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 sounds like a good change in general. Maybe that's a different story, but should we look for the cid header in the request to allow following correlations even through content access?
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.
Maybe yeah, we would also need to expose the value to be used in logging for the content app, currently this change is solely to allow for dispatching tasks from the content app.