Skip to content

Commit

Permalink
Add smart_handler as the default for api.Client
Browse files Browse the repository at this point in the history
This handler can decide which handler to use based
on content response.
  • Loading branch information
rochacbruno committed Apr 16, 2019
1 parent b0a3e8a commit 14fdbf6
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 23 deletions.
51 changes: 39 additions & 12 deletions pulp_smash/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,41 @@ def task_handler(client, response):
return done_task


def smart_handler(client, response):
"""Decides which handler to call based on response content.
Do the following:
1. Pass response through safe_handler to handle 202 and raise_for_status.
2. Return the response if it is not Pulp 3.
3. Return the response if it is not application/json type.
4. Pass response through task_handler if is JSON 202 with 'task'.
5. Pass response through page_handler if is JSON but not 202 with 'task'.
"""
# safe_handler Will raise_for_Status, handle 202 and pool tasks
response = safe_handler(client, response)

try:
check_pulp3_restriction(client)
except ValueError:
# If pulp is not 3+ return the result of safe_handler by default
return response

ctype = response.headers.get("Content-Type")
is_202 = response.status_code == 202

if ctype != "application/json":
# Not a valid JSON, return pure response
return response

# We got JSON is that a task call report?
if is_202 and "task" in response.json():
return task_handler(client, response)

# Its JSON, it is not a Task, default to page_handler
return page_handler(client, response)


class Client:
"""A convenience object for working with an API.
Expand Down Expand Up @@ -317,6 +352,7 @@ class Client:
* :func:`pulp_smash.api.json_handler`
* :func:`pulp_smash.api.page_handler`
* :func:`pulp_smash.api.task_handler`
* :func:`pulp_smash.api.smart_handler`
As mentioned, this class has configurable request and response handling
mechanisms. We've covered response handling mechanisms — let's move on to
Expand Down Expand Up @@ -372,7 +408,7 @@ class Client:
:param response_handler: A callback function, invoked after each request is
made. Must accept two arguments: a
:class:`pulp_smash.config.PulpSmashConfig` object, and a
``requests.Response`` object. Defaults to :func:`safe_handler`.
``requests.Response`` object. Defaults to :func:`smart_handler`.
:param request_kwargs: A dict of parameters to send with each request. This
dict is merged into the default dict of parameters that's sent with
each request.
Expand Down Expand Up @@ -474,17 +510,8 @@ def __init__(
):
"""Initialize this object with needed instance attributes."""
self._cfg = cfg

if response_handler:
self.response_handler = response_handler
else:
self.response_handler = safe_handler

if pulp_host:
self.pulp_host = pulp_host
else:
self.pulp_host = self._cfg.get_hosts("api")[0]

self.response_handler = response_handler or smart_handler
self.pulp_host = pulp_host or self._cfg.get_hosts("api")[0]
self.request_kwargs = self._cfg.get_requests_kwargs(self.pulp_host)
self.request_kwargs["url"] = self._cfg.get_base_url(self.pulp_host)
if request_kwargs:
Expand Down
73 changes: 62 additions & 11 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,64 @@
from unittest import mock

from packaging.version import Version
from requests import Response

from pulp_smash import api, config


_HANDLER_ARGS = ("client", "response")


@mock.patch.object(api, "safe_handler", lambda *_: _[1])
@mock.patch.object(api, "task_handler", lambda *_: _[1])
@mock.patch.object(api, "page_handler", lambda *_: _[1])
class SmartHandlerTestCase(unittest.TestCase):
"""Tests for :func:`pulp_smash.api.echo_handler`."""

@property
def client(self):
"""Return a lazy client defaults to Pulp 3, creates on every call."""
return api.Client(_get_pulp_smash_config(pulp_version="3.0"))

def test_return_bare_response_when_pulp_2(self, *_):
"""Assert the passed-in ``response`` is returned if pulp is 2."""
response = Response()
client = api.Client(_get_pulp_smash_config(pulp_version="2.19"))
self.assertIs(response, api.smart_handler(client, response))

def test_return_bare_response_when_not_json(self, *_):
"""Assert the passed-in ``response`` is returned."""
response = Response()
response.headers["Content-Type"] = "text/html"
self.assertIs(response, api.smart_handler(self.client, response))

def test_task_handler_is_called_for_tasks(self, *_):
"""Assert task handler is called when 202 with task is response."""
response = Response()
response.status_code = 202
response._content = b'{"task": "1234"}'
response.headers["Content-Type"] = "application/json"
with mock.patch.object(
api, "task_handler", lambda *_: "task_handler_called"
):
self.assertEqual(
api.smart_handler(self.client, response), "task_handler_called"
)

def test_page_handler_is_called_for_json(self, *_):
"""Assert page handler is called when json without a task."""
response = Response()
response.status_code = 201
response._content = b'{"foo": "1234"}'
response.headers["Content-Type"] = "application/json"
with mock.patch.object(
api, "page_handler", lambda *_: "page_handler_called"
):
self.assertEqual(
api.smart_handler(self.client, response), "page_handler_called"
)


class EchoHandlerTestCase(unittest.TestCase):
"""Tests for :func:`pulp_smash.api.echo_handler`."""

Expand Down Expand Up @@ -215,18 +266,18 @@ def test_json_arg(self):
self.assertIs(request.call_args[1]["json"], json)


def _get_pulp_smash_config():
def _get_pulp_smash_config(**kwargs):
"""Return a config object with made-up attributes.
:rtype: pulp_smash.config.PulpSmashConfig
"""
return config.PulpSmashConfig(
pulp_auth=["admin", "admin"],
pulp_version="1!0",
pulp_selinux_enabled=True,
hosts=[
config.PulpHost(
hostname="example.com", roles={"api": {"scheme": "http"}}
)
],
)
kwargs.setdefault("pulp_auth", ["admin", "admin"])
kwargs.setdefault("pulp_version", "1!0")
kwargs.setdefault("pulp_selinux_enabled", True)
hosts = [
config.PulpHost(
hostname="example.com", roles={"api": {"scheme": "http"}}
)
]
kwargs.setdefault("hosts", hosts)
return config.PulpSmashConfig(**kwargs)

0 comments on commit 14fdbf6

Please sign in to comment.