Skip to content

Commit 258aaa7

Browse files
radofuchsRadovan Fuchs
andauthored
LCORE-1472: test structure update (#1490)
* LCORE-1472: move the config switching logic to feature files * fix potential mcp error where toolgroups would get cleared for new scenario --------- Co-authored-by: Radovan Fuchs <rfuchs@rfuchs-thinkpadp1gen7.tpb.csb>
1 parent 7d0877c commit 258aaa7

44 files changed

Lines changed: 1642 additions & 1288 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docker-compose-library.yaml

100644100755
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ services:
3838
- ./run.yaml:/app-root/run.yaml:Z
3939
- ${GCP_KEYS_PATH:-./tmp/.gcp-keys-dummy}:/opt/app-root/.gcp-keys:ro
4040
- ./tests/e2e/rag:/opt/app-root/src/.llama/storage/rag:Z
41-
- ./tests/e2e/secrets/mcp-token:/tmp/mcp-token:ro
42-
- ./tests/e2e/secrets/invalid-mcp-token:/tmp/invalid-mcp-token:ro
41+
- ./tests/e2e/secrets/mcp-token:/tmp/mcp-token:ro,z
42+
- ./tests/e2e/secrets/invalid-mcp-token:/tmp/invalid-mcp-token:ro,z
4343
environment:
4444
# LLM Provider API Keys
4545
- BRAVE_SEARCH_API_KEY=${BRAVE_SEARCH_API_KEY:-}

docker-compose.yaml

100644100755
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ services:
3030
condition: service_healthy
3131
volumes:
3232
- ./run.yaml:/opt/app-root/run.yaml:z
33+
# Host copies so `docker compose up` picks up script changes without rebuilding llama-stack
34+
- ./scripts/llama-stack-entrypoint.sh:/opt/app-root/enrich-entrypoint.sh:ro,z
35+
- ./src/llama_stack_configuration.py:/opt/app-root/llama_stack_configuration.py:ro,z
3336
- ${GCP_KEYS_PATH:-./tmp/.gcp-keys-dummy}:/opt/app-root/.gcp-keys:ro
34-
- ./lightspeed-stack.yaml:/opt/app-root/lightspeed-stack.yaml:ro
37+
- ./lightspeed-stack.yaml:/opt/app-root/lightspeed-stack.yaml:ro,z
3538
- llama-storage:/opt/app-root/src/.llama/storage
3639
- ./tests/e2e/rag:/opt/app-root/src/.llama/storage/rag:z
3740
- mock-tls-certs:/certs:ro
@@ -90,8 +93,8 @@ services:
9093
- "8080:8080"
9194
volumes:
9295
- ./lightspeed-stack.yaml:/app-root/lightspeed-stack.yaml:z
93-
- ./tests/e2e/secrets/mcp-token:/tmp/mcp-token:ro
94-
- ./tests/e2e/secrets/invalid-mcp-token:/tmp/invalid-mcp-token:ro
96+
- ./tests/e2e/secrets/mcp-token:/tmp/mcp-token:ro,z
97+
- ./tests/e2e/secrets/invalid-mcp-token:/tmp/invalid-mcp-token:ro,z
9598
environment:
9699
- OPENAI_API_KEY=${OPENAI_API_KEY}
97100
# Azure Entra ID credentials (AZURE_API_KEY is obtained dynamically)

src/llama_stack_configuration.py

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,38 @@ def setup_azure_entra_id_token(
117117
# =============================================================================
118118

119119

120+
def _dedupe_vector_io_list(entries: list[Any]) -> list[dict[str, Any]]:
121+
"""Keep the first dict per stripped ``provider_id``; keep entries without an id."""
122+
seen: set[str] = set()
123+
out: list[dict[str, Any]] = []
124+
for item in entries:
125+
if not isinstance(item, dict):
126+
continue
127+
raw_pid = item.get("provider_id")
128+
if raw_pid is None:
129+
out.append(item)
130+
continue
131+
key = str(raw_pid).strip()
132+
if not key:
133+
out.append(item)
134+
continue
135+
if key in seen:
136+
continue
137+
seen.add(key)
138+
out.append(item)
139+
return out
140+
141+
142+
def dedupe_providers_vector_io(ls_config: dict[str, Any]) -> None:
143+
"""Collapse ``providers.vector_io`` to one entry per ``provider_id``."""
144+
if "providers" not in ls_config or "vector_io" not in ls_config["providers"]:
145+
return
146+
raw = ls_config["providers"]["vector_io"]
147+
if not isinstance(raw, list):
148+
return
149+
ls_config["providers"]["vector_io"] = _dedupe_vector_io_list(raw)
150+
151+
120152
def construct_storage_backends_section(
121153
ls_config: dict[str, Any], byok_rag: list[dict[str, Any]]
122154
) -> dict[str, Any]:
@@ -312,19 +344,32 @@ def construct_vector_io_providers_section(
312344
`provider_type` set from the RAG item, and a `config` with `persistence`
313345
referencing the corresponding backend.
314346
"""
315-
output = []
347+
output: list[dict[str, Any]] = []
316348

317-
# fill-in existing vector_io entries
318349
if "providers" in ls_config and "vector_io" in ls_config["providers"]:
319-
output = ls_config["providers"]["vector_io"].copy()
350+
raw = ls_config["providers"]["vector_io"]
351+
if isinstance(raw, list):
352+
output = _dedupe_vector_io_list(raw)
353+
else:
354+
output = []
355+
356+
existing_ids = {
357+
str(p["provider_id"]).strip()
358+
for p in output
359+
if p.get("provider_id") is not None and str(p["provider_id"]).strip()
360+
}
320361

321-
# append new vector_io entries
362+
added = 0
322363
for brag in byok_rag:
323364
if not brag.get("rag_id"):
324365
raise ValueError(f"BYOK RAG entry is missing required 'rag_id': {brag}")
325-
rag_id = brag["rag_id"]
366+
rag_id = str(brag["rag_id"]).strip()
326367
backend_name = f"byok_{rag_id}_storage"
327368
provider_id = f"byok_{rag_id}"
369+
if provider_id in existing_ids:
370+
continue
371+
existing_ids.add(provider_id)
372+
added += 1
328373
output.append(
329374
{
330375
"provider_id": provider_id,
@@ -339,7 +384,7 @@ def construct_vector_io_providers_section(
339384
)
340385
logger.info(
341386
"Added %s items into providers/vector_io section, total items %s",
342-
len(byok_rag),
387+
added,
343388
len(output),
344389
)
345390
return output
@@ -354,6 +399,7 @@ def enrich_byok_rag(ls_config: dict[str, Any], byok_rag: list[dict[str, Any]]) -
354399
"""
355400
if len(byok_rag) == 0:
356401
logger.info("BYOK RAG is not configured: skipping")
402+
dedupe_providers_vector_io(ls_config)
357403
return
358404

359405
logger.info("Enriching Llama Stack config with BYOK RAG")
@@ -567,6 +613,8 @@ def generate_configuration(
567613
with open(input_file, "r", encoding="utf-8") as file:
568614
ls_config = yaml.safe_load(file)
569615

616+
dedupe_providers_vector_io(ls_config)
617+
570618
# Enrichment: Azure Entra ID token
571619
setup_azure_entra_id_token(config.get("azure_entra_id"), env_file)
572620

@@ -576,6 +624,8 @@ def generate_configuration(
576624
# Enrichment: Solr - enabled when "okp" appears in either inline or tool list
577625
enrich_solr(ls_config, config.get("rag", {}), config.get("okp", {}))
578626

627+
dedupe_providers_vector_io(ls_config)
628+
579629
logger.info("Writing Llama Stack configuration into file %s", output_file)
580630

581631
with open(output_file, "w", encoding="utf-8") as file:

tests/e2e/features/authorized_noop.feature

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ Feature: Authorized endpoint API tests for the noop authentication module
22

33
Background:
44
Given The service is started locally
5+
And The system is in default state
56
And REST API service prefix is /v1
7+
And the Lightspeed stack configuration directory is "tests/e2e/configuration"
8+
And The service uses the lightspeed-stack.yaml configuration
9+
And The service is restarted
610

711
Scenario: Check if the authorized endpoint works fine when user_id and auth header are not provided
8-
Given The system is in default state
912
When I access endpoint "authorized" using HTTP POST method
1013
"""
1114
{"placeholder":"abc"}
@@ -17,7 +20,6 @@ Feature: Authorized endpoint API tests for the noop authentication module
1720
"""
1821

1922
Scenario: Check if the authorized endpoint works when auth token is not provided
20-
Given The system is in default state
2123
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
2224
Then The status code of the response is 200
2325
And The body of the response is the following
@@ -26,7 +28,6 @@ Feature: Authorized endpoint API tests for the noop authentication module
2628
"""
2729

2830
Scenario: Check if the authorized endpoint works when user_id is not provided
29-
Given The system is in default state
3031
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
3132
When I access endpoint "authorized" using HTTP POST method without user_id
3233
Then The status code of the response is 200
@@ -36,7 +37,6 @@ Feature: Authorized endpoint API tests for the noop authentication module
3637
"""
3738

3839
Scenario: Check if the authorized endpoint rejects empty user_id
39-
Given The system is in default state
4040
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
4141
When I access endpoint "authorized" using HTTP POST method with user_id ""
4242
Then The status code of the response is 400
@@ -46,7 +46,6 @@ Feature: Authorized endpoint API tests for the noop authentication module
4646
"""
4747

4848
Scenario: Check if the authorized endpoint works when providing proper user_id
49-
Given The system is in default state
5049
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
5150
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
5251
Then The status code of the response is 200

tests/e2e/features/authorized_noop_token.feature

Lines changed: 5 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,14 @@ Feature: Authorized endpoint API tests for the noop-with-token authentication mo
33

44
Background:
55
Given The service is started locally
6+
And The system is in default state
7+
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
68
And REST API service prefix is /v1
7-
8-
Scenario: Check if the authorized endpoint fails when user_id and auth header are not provided
9-
Given The system is in default state
10-
When I access endpoint "authorized" using HTTP POST method
11-
"""
12-
{"placeholder":"abc"}
13-
"""
14-
Then The status code of the response is 401
15-
And The body of the response is the following
16-
"""
17-
{
18-
"detail": {
19-
"response": "Missing or invalid credentials provided by client",
20-
"cause": "No Authorization header found"
21-
}
22-
}
23-
"""
9+
And the Lightspeed stack configuration directory is "tests/e2e/configuration"
10+
And The service uses the lightspeed-stack-auth-noop-token.yaml configuration
11+
And The service is restarted
2412

2513
Scenario: Check if the authorized endpoint works when user_id is not provided
26-
Given The system is in default state
27-
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
2814
When I access endpoint "authorized" using HTTP POST method without user_id
2915
Then The status code of the response is 200
3016
And The body of the response is the following
@@ -33,8 +19,6 @@ Feature: Authorized endpoint API tests for the noop-with-token authentication mo
3319
"""
3420

3521
Scenario: Check if the authorized endpoint rejects empty user_id
36-
Given The system is in default state
37-
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
3822
When I access endpoint "authorized" using HTTP POST method with user_id ""
3923
Then The status code of the response is 400
4024
And The body of the response is the following
@@ -43,40 +27,9 @@ Feature: Authorized endpoint API tests for the noop-with-token authentication mo
4327
"""
4428

4529
Scenario: Check if the authorized endpoint works when providing proper user_id
46-
Given The system is in default state
47-
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
4830
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
4931
Then The status code of the response is 200
5032
And The body of the response is the following
5133
"""
5234
{"user_id": "test_user","username": "lightspeed-user","skip_userid_check": true}
5335
"""
54-
55-
Scenario: Check if the authorized endpoint works with proper user_id but bearer token is not present
56-
Given The system is in default state
57-
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
58-
Then The status code of the response is 401
59-
And The body of the response is the following
60-
"""
61-
{
62-
"detail": {
63-
"response": "Missing or invalid credentials provided by client",
64-
"cause": "No Authorization header found"
65-
}
66-
}
67-
"""
68-
69-
Scenario: Check if the authorized endpoint works when auth token is malformed
70-
Given The system is in default state
71-
And I set the Authorization header to BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
72-
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
73-
Then The status code of the response is 401
74-
And The body of the response is the following
75-
"""
76-
{
77-
"detail": {
78-
"response": "Missing or invalid credentials provided by client",
79-
"cause": "No token found in Authorization header"
80-
}
81-
}
82-
"""

tests/e2e/features/authorized_rh_identity.feature

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,13 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
33

44
Background:
55
Given The service is started locally
6+
And The system is in default state
67
And REST API service prefix is /v1
7-
8-
Scenario: Request fails when x-rh-identity header is missing
9-
Given The system is in default state
10-
When I access endpoint "authorized" using HTTP POST method
11-
"""
12-
{"placeholder":"abc"}
13-
"""
14-
Then The status code of the response is 401
15-
And The body of the response is the following
16-
"""
17-
{"detail": "Missing x-rh-identity header"}
18-
"""
8+
And the Lightspeed stack configuration directory is "tests/e2e/configuration"
9+
And The service uses the lightspeed-stack-auth-rh-identity.yaml configuration
10+
And The service is restarted
1911

2012
Scenario: Request fails when identity field is missing
21-
Given The system is in default state
2213
And I set the x-rh-identity header with JSON
2314
"""
2415
{"entitlements": {"rhel": {"is_entitled": true}}}
@@ -31,7 +22,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
3122
And The body of the response contains Invalid identity data
3223

3324
Scenario: Request succeeds with valid User identity and required entitlements
34-
Given The system is in default state
3525
And I set the x-rh-identity header with valid User identity
3626
| field | value |
3727
| user_id | test-user-123 |
@@ -49,7 +39,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
4939
"""
5040

5141
Scenario: Request succeeds with valid System identity and required entitlements
52-
Given The system is in default state
5342
And I set the x-rh-identity header with valid System identity
5443
| field | value |
5544
| cn | c87dcb4c-8af1-40dd-878e-60c744edddd0 |
@@ -67,7 +56,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
6756
"""
6857

6958
Scenario: Request fails when required entitlement is missing
70-
Given The system is in default state
7159
And I set the x-rh-identity header with valid User identity
7260
| field | value |
7361
| user_id | test-user-123 |
@@ -82,7 +70,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
8270
And The body of the response contains Insufficient entitlements
8371

8472
Scenario: Request fails when entitlement exists but is_entitled is false
85-
Given The system is in default state
8673
And I set the x-rh-identity header with JSON
8774
"""
8875
{
@@ -102,7 +89,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
10289
And The body of the response contains Insufficient entitlements
10390

10491
Scenario: Request fails when User identity is missing user_id
105-
Given The system is in default state
10692
And I set the x-rh-identity header with JSON
10793
"""
10894
{
@@ -122,7 +108,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
122108
And The body of the response contains Invalid identity data
123109

124110
Scenario: Request fails when User identity is missing username
125-
Given The system is in default state
126111
And I set the x-rh-identity header with JSON
127112
"""
128113
{
@@ -142,7 +127,6 @@ Feature: Authorized endpoint API tests for the rh-identity authentication module
142127
And The body of the response contains Invalid identity data
143128

144129
Scenario: Request fails when System identity is missing cn
145-
Given The system is in default state
146130
And I set the x-rh-identity header with JSON
147131
"""
148132
{

0 commit comments

Comments
 (0)