diff --git a/pyproject.toml b/pyproject.toml index aa60a92ef..c0ca9df73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dcicsnovault" -version = "8.0.1" +version = "8.0.2b0" description = "Storage support for 4DN Data Portals." authors = ["4DN-DCIC Team "] license = "MIT" diff --git a/snovault/embed.py b/snovault/embed.py index 176438b4d..8ab3c5f8c 100644 --- a/snovault/embed.py +++ b/snovault/embed.py @@ -1,12 +1,14 @@ import logging from copy import deepcopy from posixpath import join +from typing import Union from pyramid.compat import ( native_, unquote_bytes_to_wsgi, ) from pyramid.httpexceptions import HTTPNotFound +from pyramid.request import Request from .interfaces import CONNECTION @@ -164,16 +166,7 @@ def _embed(request, path, as_user='EMBED'): """ # Carl: the subrequest is 'built' here, but not actually invoked subreq = make_subrequest(request, path) - # these attributes are propogated across the subrequest - subreq.override_renderer = 'null_renderer' - subreq._indexing_view = request._indexing_view - subreq._aggregate_for = request._aggregate_for - subreq._aggregated_items = request._aggregated_items - subreq._sid_cache = request._sid_cache - if as_user is not True: - if 'HTTP_COOKIE' in subreq.environ: - del subreq.environ['HTTP_COOKIE'] - subreq.remote_user = as_user + _set_subrequest_attributes(subreq, request, as_user=as_user) # _linked_uuids are populated in item_view_object of resource_views.py try: result = request.invoke_subrequest(subreq) @@ -190,6 +183,34 @@ def _embed(request, path, as_user='EMBED'): '_sid_cache': subreq._sid_cache} +def _set_subrequest_attributes( + subrequest: Request, request: Request, as_user: Union[str, bool] = False +) -> None: + subrequest.override_renderer = 'null_renderer' + _set_propagated_attributes(subrequest, request) + if as_user is not True: + _remove_http_cookie_and_set_user(subrequest, as_user) + + +def _set_propagated_attributes(subrequest: Request, request: Request) -> None: + subrequest._indexing_view = request._indexing_view + subrequest._aggregate_for = request._aggregate_for + subrequest._aggregated_items = request._aggregated_items + subrequest._sid_cache = request._sid_cache + try: + subrequest._stats = request._stats + except AttributeError: + subrequest._stats = {} + + +def _remove_http_cookie_and_set_user( + subrequest: Request, remote_user: Union[str, bool] +) -> None: + if 'HTTP_COOKIE' in subrequest.environ: + del subrequest.environ['HTTP_COOKIE'] + subrequest.remote_user = remote_user + + class NullRenderer: '''Sets result value directly as response. ''' diff --git a/snovault/tests/test_embed.py b/snovault/tests/test_embed.py new file mode 100644 index 000000000..0e969d479 --- /dev/null +++ b/snovault/tests/test_embed.py @@ -0,0 +1,84 @@ +from typing import Any, Dict, Optional, Union +from unittest.mock import create_autospec, Mock + +import pytest +from pyramid.request import Request + +from ..embed import _set_subrequest_attributes + + +DEFAULT_PARENT_REQUEST_ATTRIBUTES = { + "_indexing_view": "foo", + "_aggregate_for": "bar", + "_aggregated_items": "something", + "_sid_cache": "else", +} +DEFAULT_SUBREQUEST_ATTRIBUTES = {"environ": {"HTTP_COOKIE": "foobar", "fu": "bur"}} +DEFAULT_PROPAGATED_ATTRIBUTES = { + "override_renderer": "null_renderer", + "_stats": {}, + **DEFAULT_PARENT_REQUEST_ATTRIBUTES, +} + + +def _make_mock_request(attributes_to_set: Dict[str, Any]) -> Mock: + mock_request = create_autospec(Request, instance=True) + for attribute_name, attribute_value in attributes_to_set.items(): + setattr(mock_request, attribute_name, attribute_value) + return mock_request + + +def _make_mock_parent_request( + attributes_to_set: Optional[Dict[str, Any]] = None +) -> Mock: + if attributes_to_set is None: + attributes_to_set = {} + attributes_to_set.update(DEFAULT_PARENT_REQUEST_ATTRIBUTES) + return _make_mock_request(attributes_to_set) + + +def _make_mock_subrequest() -> Mock: + return _make_mock_request(DEFAULT_SUBREQUEST_ATTRIBUTES) + + +@pytest.mark.parametrize( + "subrequest,parent_request,as_user,expected_attributes", + [ + ( + _make_mock_subrequest(), + _make_mock_parent_request(), + True, + {**DEFAULT_PROPAGATED_ATTRIBUTES, **DEFAULT_SUBREQUEST_ATTRIBUTES}, + ), + ( + _make_mock_subrequest(), + _make_mock_parent_request({"_stats": "some_stats"}), + True, + { + **DEFAULT_PROPAGATED_ATTRIBUTES, + **DEFAULT_SUBREQUEST_ATTRIBUTES, + "_stats": "some_stats", + }, + ), + ( + _make_mock_subrequest(), + _make_mock_parent_request(), + False, + { + **DEFAULT_PROPAGATED_ATTRIBUTES, + **DEFAULT_SUBREQUEST_ATTRIBUTES, + "environ": {"fu": "bur"}, + "remote_user": False, + }, + ), + ], +) +def test_set_subrequest_attributes( + subrequest: Mock, + parent_request: Mock, + as_user: Union[bool, str], + expected_attributes: Dict[str, Any], +) -> None: + _set_subrequest_attributes(subrequest, parent_request, as_user=as_user) + for attribute_name, attribute_value in expected_attributes.items(): + assert getattr(subrequest, attribute_name) == attribute_value