Skip to content

Commit 38857e8

Browse files
committed
test(e2e): add rlsapi v1 /infer endpoint tests
- Add rlsapi_v1.feature with 7 test scenarios - Add rlsapi_v1.py step definitions for response validation - Update test_list.txt to include new feature file Implements LCORE-1223 Signed-off-by: Major Hayden <major@redhat.com>
1 parent 71b93ea commit 38857e8

10 files changed

Lines changed: 219 additions & 0 deletions

tests/e2e/configuration/library-mode/lightspeed-stack-auth-noop-token.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ conversation_cache:
2323

2424
authentication:
2525
module: "noop-with-token"
26+
inference:
27+
default_provider: openai
28+
default_model: gpt-4o-mini

tests/e2e/configuration/library-mode/lightspeed-stack-rbac.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ authorization:
7474
- "get_tools"
7575
- "info"
7676
- "model_override"
77+
- "rlsapi_v1_infer"
7778
# Viewer role can only read (no mutations)
7879
- role: "viewer"
7980
actions:

tests/e2e/configuration/library-mode/lightspeed-stack.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ user_data_collection:
1717
transcripts_storage: "/tmp/data/transcripts"
1818
authentication:
1919
module: "noop"
20+
inference:
21+
default_provider: openai
22+
default_model: gpt-4o-mini
2023
mcp_servers:
2124
# Mock server with client-provided auth - should appear in mcp-auth/client-options response
2225
- name: "github-api"

tests/e2e/configuration/server-mode/lightspeed-stack-auth-noop-token.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,6 @@ conversation_cache:
2929

3030
authentication:
3131
module: "noop-with-token"
32+
inference:
33+
default_provider: openai
34+
default_model: gpt-4o-mini

tests/e2e/configuration/server-mode/lightspeed-stack-rbac.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ authorization:
7575
- "get_tools"
7676
- "info"
7777
- "model_override"
78+
- "rlsapi_v1_infer"
7879
# Viewer role can only read (no mutations)
7980
- role: "viewer"
8081
actions:

tests/e2e/configuration/server-mode/lightspeed-stack.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ user_data_collection:
1818
transcripts_storage: "/tmp/data/transcripts"
1919
authentication:
2020
module: "noop"
21+
inference:
22+
default_provider: openai
23+
default_model: gpt-4o-mini
2124
mcp_servers:
2225
# Mock server with client-provided auth - should appear in mcp-auth/client-options response
2326
- name: "github-api"
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
@Authorized
2+
Feature: rlsapi v1 /infer endpoint API tests
3+
4+
Background:
5+
Given The service is started locally
6+
And REST API service prefix is /v1
7+
8+
Scenario: Basic inference with minimal request (question only)
9+
Given The system is in default state
10+
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
11+
When I use "infer" to ask question with authorization header
12+
"""
13+
{"question": "How do I list files in Linux?"}
14+
"""
15+
Then The status code of the response is 200
16+
And The rlsapi response should have valid structure
17+
18+
Scenario: Inference with full context (systeminfo populated)
19+
Given The system is in default state
20+
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
21+
When I use "infer" to ask question with authorization header
22+
"""
23+
{"question": "How do I configure SELinux?", "context": {"systeminfo": {"os": "RHEL", "version": "9.3", "arch": "x86_64"}}}
24+
"""
25+
Then The status code of the response is 200
26+
And The rlsapi response should have valid structure
27+
28+
Scenario: Request without authorization returns 401
29+
Given The system is in default state
30+
When I use "infer" to ask question
31+
"""
32+
{"question": "How do I list files?"}
33+
"""
34+
Then The status code of the response is 401
35+
And The body of the response is the following
36+
"""
37+
{
38+
"detail": {
39+
"response": "Missing or invalid credentials provided by client",
40+
"cause": "No Authorization header found"
41+
}
42+
}
43+
"""
44+
45+
Scenario: Request with empty bearer token returns 401
46+
Given The system is in default state
47+
And I set the Authorization header to Bearer
48+
When I use "infer" to ask question with authorization header
49+
"""
50+
{"question": "How do I list files?"}
51+
"""
52+
Then The status code of the response is 401
53+
And The body of the response contains No token found in Authorization header
54+
55+
Scenario: Empty/whitespace question returns 422
56+
Given The system is in default state
57+
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
58+
When I use "infer" to ask question with authorization header
59+
"""
60+
{"question": " "}
61+
"""
62+
Then The status code of the response is 422
63+
And The body of the response contains Question cannot be empty
64+
65+
Scenario: Response contains valid structure (data.text, data.request_id)
66+
Given The system is in default state
67+
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
68+
When I use "infer" to ask question with authorization header
69+
"""
70+
{"question": "What is RHEL?"}
71+
"""
72+
Then The status code of the response is 200
73+
And The rlsapi response should have valid structure
74+
75+
Scenario: Multiple requests generate unique request_ids
76+
Given The system is in default state
77+
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
78+
When I use "infer" to ask question with authorization header
79+
"""
80+
{"question": "First question"}
81+
"""
82+
Then The status code of the response is 200
83+
And I store the rlsapi request_id
84+
When I use "infer" to ask question with authorization header
85+
"""
86+
{"question": "Second question"}
87+
"""
88+
Then The status code of the response is 200
89+
And The rlsapi request_id should be different from the stored one
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@RBAC
2+
Feature: rlsapi v1 /infer endpoint error response tests
3+
4+
Tests for error conditions on the rlsapi v1 /infer endpoint including
5+
authorization failures (403) and service unavailability (503).
6+
7+
Background:
8+
Given The service is started locally
9+
And REST API service prefix is /v1
10+
11+
# ============================================
12+
# Authorization - 403 Forbidden
13+
# ============================================
14+
15+
Scenario: User without rlsapi_v1_infer permission returns 403
16+
Given The system is in default state
17+
And I authenticate as "viewer" user
18+
When I use "infer" to ask question with authorization header
19+
"""
20+
{"question": "How do I list files?"}
21+
"""
22+
Then The status code of the response is 403
23+
And The body of the response contains does not have permission
24+
25+
Scenario: User with rlsapi_v1_infer permission can access endpoint
26+
Given The system is in default state
27+
And I authenticate as "user" user
28+
When I use "infer" to ask question with authorization header
29+
"""
30+
{"question": "How do I list files?"}
31+
"""
32+
Then The status code of the response is 200
33+
And The rlsapi response should have valid structure
34+
35+
# ============================================
36+
# Service Unavailable - 503
37+
# ============================================
38+
39+
@skip-in-library-mode
40+
Scenario: Returns 503 when llama-stack connection is broken
41+
Given The system is in default state
42+
And I authenticate as "user" user
43+
And The llama-stack connection is disrupted
44+
When I use "infer" to ask question with authorization header
45+
"""
46+
{"question": "How do I list files?"}
47+
"""
48+
Then The status code of the response is 503
49+
And The body of the response contains Llama Stack
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""rlsapi v1 endpoint test steps."""
2+
3+
from behave import then, step # pyright: ignore[reportAttributeAccessIssue]
4+
from behave.runner import Context
5+
6+
7+
@then("The rlsapi response should have valid structure")
8+
def check_rlsapi_response_structure(context: Context) -> None:
9+
"""Check that rlsapi v1 response has valid structure.
10+
11+
Validates that the response contains:
12+
- data.text (non-empty string)
13+
- data.request_id (non-empty string)
14+
"""
15+
assert context.response is not None, "Request needs to be performed first"
16+
response_json = context.response.json()
17+
18+
assert "data" in response_json, "Response missing 'data' field"
19+
data = response_json["data"]
20+
21+
assert "text" in data, "Response data missing 'text' field"
22+
assert isinstance(data["text"], str), "data.text must be a string"
23+
assert len(data["text"]) > 0, "data.text must not be empty"
24+
25+
assert "request_id" in data, "Response data missing 'request_id' field"
26+
assert isinstance(data["request_id"], str), "data.request_id must be a string"
27+
assert len(data["request_id"]) > 0, "data.request_id must not be empty"
28+
29+
30+
@step("I store the rlsapi request_id")
31+
def store_rlsapi_request_id(context: Context) -> None:
32+
"""Store the request_id from rlsapi response for later comparison."""
33+
assert context.response is not None, "Request needs to be performed first"
34+
response_json = context.response.json()
35+
36+
assert "data" in response_json, "Response missing 'data' field"
37+
assert "request_id" in response_json["data"], "Response data missing 'request_id'"
38+
assert isinstance(
39+
response_json["data"]["request_id"], str
40+
), "data.request_id must be a string"
41+
assert (
42+
len(response_json["data"]["request_id"]) > 0
43+
), "data.request_id must not be empty"
44+
45+
context.stored_request_id = response_json["data"]["request_id"]
46+
47+
48+
@then("The rlsapi request_id should be different from the stored one")
49+
def check_rlsapi_request_id_different(context: Context) -> None:
50+
"""Verify that the current request_id differs from the stored one."""
51+
assert context.response is not None, "Request needs to be performed first"
52+
assert hasattr(context, "stored_request_id"), "No request_id was stored previously"
53+
54+
response_json = context.response.json()
55+
assert "data" in response_json, "Response missing 'data' field"
56+
assert "request_id" in response_json["data"], "Response data missing 'request_id'"
57+
58+
current_request_id = response_json["data"]["request_id"]
59+
assert isinstance(current_request_id, str), "data.request_id must be a string"
60+
assert len(current_request_id) > 0, "data.request_id must not be empty"
61+
stored_request_id = context.stored_request_id
62+
63+
assert (
64+
current_request_id != stored_request_id
65+
), f"request_id should be unique, but got same value: {current_request_id}"

tests/e2e/test_list.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ features/feedback.feature
1010
features/health.feature
1111
features/info.feature
1212
features/query.feature
13+
features/rlsapi_v1.feature
14+
features/rlsapi_v1_errors.feature
1315
features/streaming_query.feature
1416
features/rest_api.feature
1517
features/models.feature

0 commit comments

Comments
 (0)