Skip to content

Commit

Permalink
Replace requests mocking with pook (#3562)
Browse files Browse the repository at this point in the history
* Replace `requests` mocking with `pook`

* Use `pook.use` context manager instead of `pook.on` and `pook.off`

---------

Co-authored-by: sarayourfriend <[email protected]>
  • Loading branch information
dhruvkb and sarayourfriend authored Dec 22, 2023
1 parent 8ad81f6 commit 48f435e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 89 deletions.
59 changes: 17 additions & 42 deletions api/test/unit/utils/test_watermark.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import json
from collections.abc import Callable
from dataclasses import dataclass
from pathlib import Path

import pook
import pytest
from requests import Request, Response

from api.utils.watermark import HEADERS, watermark

Expand All @@ -14,55 +12,32 @@
_MOCK_IMAGE_INFO = json.loads((_MOCK_IMAGE_PATH / "sample-image-info.json").read_text())


@dataclass
class RequestsFixture:
requests: list[Request]
response_factory: Callable[[Request], Response] = ( # noqa: E731
lambda x: RequestsFixture._default_response_factory(x)
)
@pytest.fixture
def mock_request():
with pook.use():
mock = (
pook.get("http://example.com/")
.header("User-Agent", HEADERS["User-Agent"])
.reply(200)
.body(_MOCK_IMAGE_BYTES, binary=True)
.mock
)
yield mock

@staticmethod
def _default_response_factory(req: Request) -> Response:
res = Response()
res.url = req.url
res.status_code = 200
res._content = _MOCK_IMAGE_BYTES
return res


@pytest.fixture(autouse=True)
def requests(monkeypatch) -> RequestsFixture:
fixture = RequestsFixture([])

def requests_get(url, **kwargs):
req = Request(method="GET", url=url, **kwargs)
fixture.requests.append(req)
response = fixture.response_factory(req)
return response

monkeypatch.setattr("requests.get", requests_get)

return fixture


def test_sends_UA_header(requests):
def test_watermark_image_sends_ua_header(mock_request):
watermark("http://example.com/", _MOCK_IMAGE_INFO)

assert len(requests.requests) > 0
for r in requests.requests:
assert r.headers == HEADERS
# ``pook`` will only match if UA header is sent.
assert mock_request.total_matches > 0


# Previously, wrapped titles would throw a TypeError:
# slice indices must be integers or None or have an __index__ method.
# See: https://github.com/WordPress/openverse/issues/2466
def test_long_title_wraps_correctly(requests):
def test_long_title_wraps_correctly(mock_request):
# Make the title 400 chars long
_MOCK_IMAGE_INFO_LONG_TITLE = dict(_MOCK_IMAGE_INFO)
_MOCK_IMAGE_INFO_LONG_TITLE["title"] = "a" * 400

watermark("http://example.com/", _MOCK_IMAGE_INFO_LONG_TITLE)

assert len(requests.requests) > 0
for r in requests.requests:
assert r.headers == HEADERS
assert mock_request.total_matches > 0
57 changes: 16 additions & 41 deletions api/test/unit/utils/test_waveform.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import json
from collections.abc import Callable
from dataclasses import dataclass
from io import BytesIO
from pathlib import Path

import pook
import pytest
from requests import Request, Response
from requests.structures import CaseInsensitiveDict

from api.utils.waveform import UA_STRING, download_audio

Expand All @@ -16,42 +12,21 @@
_MOCK_AUDIO_INFO = json.loads((_MOCK_AUDIO_PATH / "sample-audio-info.json").read_text())


@dataclass
class RequestsFixture:
requests: list[Request]
response_factory: Callable[[Request], Response] = ( # noqa: E731
lambda x: RequestsFixture._default_response_factory(x)
)
@pytest.fixture
def mock_request():
with pook.use():
mock = (
pook.get("http://example.org/")
.header("User-Agent", UA_STRING)
.reply(200)
.headers({"Content-Type": _MOCK_AUDIO_INFO["headers"]["Content-Type"]})
.body(_MOCK_AUDIO_BYTES, binary=True)
.mock
)
yield mock

@staticmethod
def _default_response_factory(req: Request) -> Response:
res = Response()
res.url = req.url
res.status_code = 200
res.raw = BytesIO(_MOCK_AUDIO_BYTES)
res.headers = CaseInsensitiveDict(_MOCK_AUDIO_INFO["headers"])
return res


@pytest.fixture(autouse=True)
def requests(monkeypatch) -> RequestsFixture:
fixture = RequestsFixture([])

def requests_get(url, **kwargs):
kwargs.pop("stream")
req = Request(method="GET", url=url, **kwargs)
fixture.requests.append(req)
response = fixture.response_factory(req)
return response

monkeypatch.setattr("requests.get", requests_get)

return fixture


def test_download_audio_sends_ua_header(requests):
def test_download_audio_sends_ua_header(mock_request):
download_audio("http://example.org", "abcd-1234")

assert len(requests.requests) > 0
for r in requests.requests:
assert r.headers["User-Agent"] == UA_STRING
# ``pook`` will only match if UA header is sent.
assert mock_request.total_matches > 0
9 changes: 3 additions & 6 deletions api/test/unit/views/test_image_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import pook
import pytest
from PIL import UnidentifiedImageError
from requests import Response

from api.views.image_views import ImageViewSet

Expand Down Expand Up @@ -85,11 +84,9 @@ def test_watermark_raises_424_for_invalid_image(api_client):
def test_watermark_raises_424_for_404_image(api_client):
image = ImageFactory.create()

with patch("requests.get") as mock_get:
mock_get.return_value = Response()
mock_get.return_value.status_code = 404
mock_get.return_value.url = image.url
mock_get.return_value.reason = "Not Found"
with pook.use():
pook.get(image.url).reply(404)

res = api_client.get(f"/v1/images/{image.identifier}/watermark/")
assert res.status_code == 424
assert res.data["detail"] == f"404 Client Error: Not Found for url: {image.url}"
Expand Down

0 comments on commit 48f435e

Please sign in to comment.