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

DISCO-3110 Load testing the manifest endpoint #769

Merged
merged 1 commit into from
Jan 28, 2025
Merged
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
42 changes: 40 additions & 2 deletions tests/load/locustfiles/locustfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from pydantic import BaseModel

from merino.curated_recommendations.corpus_backends.protocol import Topic
from merino.providers.manifest.backends.protocol import ManifestData
from merino.providers.suggest.adm.backends.protocol import SuggestionContent
from merino.providers.suggest.adm.backends.remotesettings import (
RemoteSettingsBackend,
Expand Down Expand Up @@ -53,6 +54,7 @@

# See https://mozilla-services.github.io/merino/api.html#suggest
SUGGEST_API: str = "/api/v1/suggest"
MANIFEST_API: str = "/api/v1/manifest"
VERSION_API: str = "/__version__"
CURATED_RECOMMENDATIONS_API = "/api/v1/curated-recommendations"

Expand Down Expand Up @@ -302,7 +304,9 @@ def store_suggestions(environment, msg, **kwargs) -> None:
def on_locust_init(environment, **kwargs):
"""Register a message on worker nodes."""
if not isinstance(environment.runner, MasterRunner):
environment.runner.register_message("store_suggestions", store_suggestions)
if not hasattr(environment.runner, "_store_suggestions_registered"):
environment.runner.register_message("store_suggestions", store_suggestions)
environment.runner._store_suggestions_registered = True


class QueryData(BaseModel):
Expand Down Expand Up @@ -399,7 +403,41 @@ def top_picks_suggestions(self) -> None:
for query in queries:
self._request_suggestions(query, providers)

@task(weight=642)
@task(weight=2)
def manifest(self) -> None:
"""Send a request to get the latest website favicons manifest."""
default_headers: dict[str, str] = {
"Accept-Language": choice(LOCALES), # nosec
"User-Agent": choice(DESKTOP_FIREFOX), # nosec
}

with self.client.get(
url=MANIFEST_API,
headers=default_headers,
catch_response=True,
name=MANIFEST_API,
) as response:
if response.status_code == 0:
# Do not classify as failure
#
# 0: The HttpSession catches any requests.RequestException thrown by
# Session (caused by connection errors, timeouts or similar), instead
# returning a dummy Response object with status_code set to 0 and
# content set to None.
logger.warning("Received a response with a status code of 0.")
response.success()
return

if response.status_code != 200:
response.failure(f"{response.status_code=}, expected 200, {response.text=}")
return

# Create a pydantic model instance for validating the response content
# from Merino. This will raise a ValidationError if the response is missing
# fields which will be reported as a failure in Locust's statistics.
ManifestData(**response.json())

@task(weight=640)
def weather_suggestions(self) -> None:
"""Send multiple requests for Weather queries."""
# Firefox will do local keyword matching to trigger weather suggestions
Expand Down