Skip to content
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

Propagate subrequest stats #257

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>"]
license = "MIT"
Expand Down
41 changes: 31 additions & 10 deletions snovault/embed.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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)
Expand All @@ -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.
'''
Expand Down
84 changes: 84 additions & 0 deletions snovault/tests/test_embed.py
Original file line number Diff line number Diff line change
@@ -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