-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathconftest.py
More file actions
167 lines (137 loc) · 5.44 KB
/
conftest.py
File metadata and controls
167 lines (137 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""Module for test configurations for the integration test directory."""
from logging import LogRecord
from typing import Iterator
from unittest.mock import AsyncMock
import pytest
import orjson
from starlette.testclient import TestClient
from aiodogstatsd import Client as AioDogstatsdClient
from merino.providers.manifest import Provider
from merino.providers.manifest.backends.manifest import ManifestBackend
from merino.providers.manifest.backends.protocol import GetManifestResultCode, ManifestData
from merino.utils.gcs.gcs_uploader import GcsUploader
from contextlib import nullcontext
from merino.curated_recommendations.fakespot_backend.protocol import (
FakespotFeed,
FakespotProduct,
FAKESPOT_DEFAULT_CATEGORY_NAME,
FAKESPOT_HEADER_COPY,
FAKESPOT_FOOTER_COPY,
FakespotCTA,
FAKESPOT_CTA_COPY,
FAKESPOT_CTA_URL,
)
from merino.main import app
from merino.utils.log_data_creators import RequestSummaryLogDataModel
from tests.integration.api.types import RequestSummaryLogDataFixture
class NoOpMetricsClient(AioDogstatsdClient):
"""No-op metrics client for test usage that inherits from aiodogstatsd.Client."""
def increment(self, *args, **kwargs):
"""Do nothing instead of sending a metric increment."""
pass
def gauge(self, *args, **kwargs):
"""Do nothing instead of sending a metric gauge."""
pass
def timeit(self, *args, **kwargs):
"""Return a no-op context manager instead of timing."""
return nullcontext()
@pytest.fixture(scope="function")
def gcp_uploader(gcs_storage_client, gcs_storage_bucket) -> GcsUploader:
"""Return a custom test gcs uploader"""
return GcsUploader(
destination_gcp_project=gcs_storage_client.project,
destination_bucket_name=gcs_storage_bucket.name,
destination_cdn_hostname="",
)
@pytest.fixture(name="client")
def fixture_test_client() -> TestClient:
"""Return a FastAPI TestClient instance.
Note that this will NOT trigger event handlers (i.e. `startup` and `shutdown`) for
the app, see: https://fastapi.tiangolo.com/advanced/testing-events/
"""
return TestClient(app)
@pytest.fixture(name="client_with_events")
def fixture_test_client_with_events() -> Iterator[TestClient]:
"""Return a FastAPI TestClient instance.
This test client will trigger event handlers (i.e. `startup` and `shutdown`) for
the app, see: https://fastapi.tiangolo.com/advanced/testing-events/
"""
with TestClient(app) as client:
yield client
@pytest.fixture(name="extract_request_summary_log_data")
def fixture_extract_request_summary_log_data() -> RequestSummaryLogDataFixture:
"""Return a function that will extract the extra log data from a captured
"request.summary" log record
"""
def extract_request_summary_log_data(
record: LogRecord,
) -> RequestSummaryLogDataModel:
return RequestSummaryLogDataModel(
errno=record.__dict__["errno"],
time=record.__dict__["time"],
agent=record.__dict__["agent"],
path=record.__dict__["path"],
method=record.__dict__["method"],
lang=record.__dict__["lang"],
querystring=record.__dict__["querystring"],
code=record.__dict__["code"],
)
return extract_request_summary_log_data
def fakespot_feed() -> FakespotFeed:
"""Open JSON file for mocked fakespot products & return constructed Fakespot feed"""
with open("tests/data/fakespot_products.json", "rb") as f:
fakespot_products_json_data = orjson.loads(f.read())
fakespot_products = []
for product in fakespot_products_json_data:
fakespot_products.append(
FakespotProduct(
id=product["id"],
title=product["title"],
category=product["category"],
imageUrl=product["imageUrl"],
url=product["url"],
)
)
return FakespotFeed(
products=fakespot_products,
defaultCategoryName=FAKESPOT_DEFAULT_CATEGORY_NAME,
headerCopy=FAKESPOT_HEADER_COPY,
footerCopy=FAKESPOT_FOOTER_COPY,
cta=FakespotCTA(ctaCopy=FAKESPOT_CTA_COPY, url=FAKESPOT_CTA_URL),
)
@pytest.fixture
def mock_manifest():
"""Mock manifest data with a known icon URL."""
return {
"domains": [
{
"rank": 1,
"domain": "spotify",
"categories": ["Entertainment"],
"serp_categories": [0],
"url": "https://www.spotify.com",
"title": "Spotify",
"icon": "https://test.com/spotify-favicon.ico",
}
]
}
@pytest.fixture
def mock_manifest_backend(mock_manifest):
"""Mock ManifestBackend that returns our test data."""
backend = ManifestBackend()
backend.fetch = AsyncMock(
return_value=(GetManifestResultCode.SUCCESS, ManifestData(**mock_manifest))
)
return backend
@pytest.fixture
def manifest_provider(mock_manifest_backend):
"""Override the manifest provider fixture with our mocked data."""
provider = Provider(
backend=mock_manifest_backend,
resync_interval_sec=86400,
cron_interval_sec=3600,
)
return provider