Skip to content
Closed
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
47 changes: 40 additions & 7 deletions tests/e2e/features/steps/common_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json

import requests
from behave import given, then, when
from behave import given, then, when # pyright: ignore[reportAttributeAccessIssue]
from behave.runner import Context
from tests.e2e.utils.utils import normalize_endpoint, validate_json

Expand Down Expand Up @@ -33,10 +33,16 @@ def request_endpoint_with_body(
def request_endpoint_with_json(
context: Context, endpoint: str, hostname: str, port: int
) -> None:
"""Perform a request to the local server with a given JSON in the request."""
"""
Sends an HTTP GET request with a JSON payload to the specified endpoint and stores the response in the context.

The JSON payload is parsed from `context.text`, which must not be None. The response is saved to `context.response`.
"""
# initial value
context.response = None

assert context.text is not None, "Payload needs to be specified"

# perform REST API call
context.response = requests.get(
f"http://{hostname}:{port}/{endpoint}",
Expand All @@ -51,9 +57,15 @@ def request_endpoint_with_json(
def request_endpoint_with_url_params(
context: Context, endpoint: str, hostname: str, port: int
) -> None:
"""Perform a request to the server defined by URL to a given endpoint."""
"""
Send an HTTP GET request to the specified endpoint with URL query parameters extracted from the context table.

The function asserts that `context.table` is provided and uses its rows to build the query parameters for the request. The HTTP response is stored in `context.response`.
"""
params = {}

assert context.table is not None, "Request parameters needs to be specified"

for row in context.table:
name = row["param"]
value = row["value"]
Expand Down Expand Up @@ -118,8 +130,13 @@ def check_content_type(context: Context, content_type: str) -> None:

@then("The body of the response has the following schema")
def check_response_body_schema(context: Context) -> None:
"""Check that response body is compliant with a given schema."""
"""
Validates that the JSON response body matches a schema provided in the test context.

Asserts that a response has been received and that a schema is present in `context.text`. Loads the schema from `context.text` and validates the response body against it using the `validate_json` utility.
"""
assert context.response is not None, "Request needs to be performed first"
assert context.text is not None, "Response does not contain any payload"
schema = json.loads(context.text)
body = context.response.json()

Expand All @@ -137,8 +154,13 @@ def check_response_body_contains(context: Context, substring: str) -> None:

@then("The body of the response is the following")
def check_prediction_result(context: Context) -> None:
"""Check the content of the response to be exactly the same."""
"""
Asserts that the JSON response body matches exactly the expected JSON payload provided in the test context.

Raises an assertion error if the response is missing, the expected payload is not provided, or if the actual and expected JSON objects differ.
"""
assert context.response is not None, "Request needs to be performed first"
assert context.text is not None, "Response does not contain any payload"
expected_body = json.loads(context.text)
result = context.response.json()

Expand All @@ -148,8 +170,14 @@ def check_prediction_result(context: Context) -> None:

@then('The body of the response, ignoring the "{field}" field, is the following')
def check_prediction_result_ignoring_field(context: Context, field: str) -> None:
"""Check the content of the response to be exactly the same."""
"""
Asserts that the JSON response body matches the expected JSON payload, ignoring a specified field.

Parameters:
field (str): The name of the field to exclude from both the actual and expected JSON objects during comparison.
"""
assert context.response is not None, "Request needs to be performed first"
assert context.text is not None, "Response does not contain any payload"
expected_body = json.loads(context.text).copy()
result = context.response.json().copy()

Expand Down Expand Up @@ -212,11 +240,16 @@ def access_rest_api_endpoint_get(context: Context, endpoint: str) -> None:

@when("I access endpoint {endpoint:w} using HTTP POST method")
def access_rest_api_endpoint_post(context: Context, endpoint: str) -> None:
"""Send GET HTTP request to tested service."""
"""
Send a POST HTTP request with a JSON payload to a REST API endpoint constructed from the given context and endpoint.

The JSON payload is loaded from `context.text`, which must not be None. The response is stored in `context.response`.
"""
base = f"http://{context.hostname}:{context.port}"
path = f"{context.api_prefix}/{endpoint}".replace("//", "/")
url = base + path

assert context.text is not None, "Payload needs to be specified"
data = json.loads(context.text)
# initial value
context.response = None
Expand Down
10 changes: 8 additions & 2 deletions tests/e2e/features/steps/llm_query_response.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""LLM query and response steps."""

import requests
from behave import then, when
from behave import then, when # pyright: ignore[reportAttributeAccessIssue]
from behave.runner import Context

DEFAULT_LLM_TIMEOUT = 60
Expand Down Expand Up @@ -36,11 +36,17 @@ def check_llm_response_not_truncated(context: Context) -> None:

@then("The response should contain following fragments")
def check_fragments_in_response(context: Context) -> None:
"""Check if the LLM response contain list of fragments."""
"""
Validate that all specified fragments are present in the LLM response.

Checks that the HTTP response exists and contains a "response" field. For each fragment listed in the scenario's table under "Fragments in LLM response", asserts that it appears as a substring in the LLM's response. Raises an assertion error if any fragment is missing or if the fragments table is not provided.
"""
assert context.response is not None
response_json = context.response.json()
response = response_json["response"]

assert context.table is not None, "Fragments are not specified in table"

for fragment in context.table:
expected = fragment["Fragments in LLM response"]
assert (
Expand Down
Loading