Skip to content

Commit 60445bc

Browse files
committed
feat: integration tests for agw auth methods
1 parent e429fb1 commit 60445bc

9 files changed

Lines changed: 360 additions & 25 deletions

File tree

.env_integration_tests.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ CLOUD_SDK_CFG_SDM_DEFAULT_UAA='{"url":"https://your-auth-url","clientid":"your-c
1919

2020
CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_APPLICATION_URL=https://your-agent-memory-api-url-here
2121
CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_UAA='{"url":"https://your-auth-url","clientid":"your-client-id","clientsecret":"your-client-secret"}'
22+
23+
APPFND_CONHOS_LANDSCAPE=your-landscape-here
24+
AGW_USER_TOKEN=your-user-jwt-here

docs/INTEGRATION_TESTS.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,28 @@ CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_APPLICATION_URL=https://your-agent-memor
7474
CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_UAA='{"url":"https://your-auth-url","clientid":"your-client-id","clientsecret":"your-client-secret"}'
7575
```
7676

77+
### Agent Gateway Integration Tests
78+
79+
Agent Gateway integration tests use the LoB agent flow via the Destination Service. Configure the following variables in `.env_integration_tests`:
80+
81+
```bash
82+
# Destination Service (required by the LoB agent flow)
83+
CLOUD_SDK_CFG_DESTINATION_DEFAULT_CLIENTID=your-destination-client-id-here
84+
CLOUD_SDK_CFG_DESTINATION_DEFAULT_CLIENTSECRET=your-destination-client-secret-here
85+
CLOUD_SDK_CFG_DESTINATION_DEFAULT_URL=https://your-destination-auth-url-here
86+
CLOUD_SDK_CFG_DESTINATION_DEFAULT_URI=https://your-destination-configuration-uri-here
87+
CLOUD_SDK_CFG_DESTINATION_DEFAULT_IDENTITYZONE=your-identity-zone-here
88+
89+
# Landscape suffix used to resolve the IAS destination name
90+
APPFND_CONHOS_LANDSCAPE=your-landscape-here
91+
92+
# User JWT for token exchange scenarios (get_user_auth)
93+
# If not set, user auth scenarios are automatically skipped
94+
AGW_USER_TOKEN=your-user-jwt-here
95+
```
96+
97+
The tenant subdomain is hardcoded to `731465182` in the test fixtures.
98+
7799
## Running Integration Tests
78100

79101
```bash
@@ -85,6 +107,7 @@ uv run pytest tests/core/integration/auditlog -v
85107
uv run pytest tests/objectstore/integration/ -v
86108
uv run pytest tests/destination/integration/ -v
87109
uv run pytest tests/agent_memory/integration/ -v
110+
uv run pytest tests/agentgateway/integration/ -v
88111
```
89112

90113
### BDD Scenarios

src/sap_cloud_sdk/agentgateway/_lob.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
"""
77

88
import asyncio
9-
import base64
109
import logging
1110
import os
1211
import uuid
@@ -61,19 +60,19 @@ def _fetch_auth_token(
6160
tenant_subdomain: str,
6261
options: ConsumptionOptions | None = None,
6362
) -> tuple[str, str]:
64-
"""Fetch raw access token and gateway URL from destination service.
63+
"""Fetch auth token and gateway URL from destination service.
6564
66-
Extracts the raw JWT by base64-decoding the token value field
67-
from the destination service response, and the gateway URL from
68-
the destination's URL property.
65+
Extracts the raw JWT from the Authorization header value returned by the
66+
destination service (e.g. strips the "Bearer " prefix from "Bearer <jwt>"),
67+
and the gateway URL from the destination's URL property.
6968
7069
Args:
7170
dest_name: Destination name.
7271
tenant_subdomain: Tenant subdomain for multi-tenant lookup.
7372
options: Consumption options (fragment_name, user_token).
7473
7574
Returns:
76-
Tuple of (raw_access_token, gateway_url).
75+
Tuple of (raw_jwt, gateway_url).
7776
7877
Raises:
7978
MCPServerNotFoundError: If no auth token is returned.
@@ -91,14 +90,17 @@ def _fetch_auth_token(
9190
f"No auth token returned for destination '{dest_name}'"
9291
)
9392

94-
token_value = dest.auth_tokens[0].value
95-
if not token_value:
96-
raise MCPServerNotFoundError(f"Empty token value for destination '{dest_name}'")
93+
auth_token = dest.auth_tokens[0]
94+
header_value = auth_token.http_header.get("value") or ""
95+
if not header_value:
96+
raise MCPServerNotFoundError(f"Empty auth header for destination '{dest_name}'")
97+
98+
# Strip "Bearer " prefix — AuthResult.access_token is always a raw JWT
99+
raw_token = header_value.removeprefix("Bearer ").strip()
97100

98-
token = base64.b64decode(token_value).decode("utf-8")
99101
gateway_url = (dest.url or "").rstrip("/")
100102

101-
return token, gateway_url
103+
return raw_token, gateway_url
102104

103105

104106
def list_mcp_fragments(tenant_subdomain: str) -> list:

src/sap_cloud_sdk/agentgateway/_models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class AuthResult:
1111
Contains the access token and the Agent Gateway URL.
1212
1313
Attributes:
14-
access_token: Raw JWT access token string.
14+
access_token: Raw JWT access token (no "Bearer " prefix).
1515
gateway_url: Agent Gateway base URL (no trailing slash).
1616
1717
Example:

tests/agentgateway/integration/__init__.py

Whitespace-only changes.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Feature: Agent Gateway Auth Integration
2+
As a developer using the SDK
3+
I want to fetch auth credentials from the Agent Gateway
4+
So that I can make authenticated requests to MCP servers
5+
6+
Background:
7+
Given the Agent Gateway client is available
8+
9+
Scenario: Get system auth returns a valid AuthResult
10+
When I call get_system_auth
11+
Then the result should be an AuthResult
12+
And the access_token should be a non-empty string
13+
And the gateway_url should be a non-empty string
14+
And the gateway_url should have no trailing slash
15+
And the access_token should not start with "Bearer "
16+
17+
Scenario: Get user auth returns a valid AuthResult
18+
Given I have a valid user token
19+
When I call get_user_auth with the user token
20+
Then the result should be an AuthResult
21+
And the access_token should be a non-empty string
22+
And the gateway_url should be a non-empty string
23+
And the gateway_url should have no trailing slash
24+
And the access_token should not start with "Bearer "
25+
26+
Scenario: Get user auth accepts a callable user token
27+
Given I have a valid user token
28+
When I call get_user_auth with a callable returning the user token
29+
Then the result should be an AuthResult
30+
And the access_token should be a non-empty string
31+
32+
Scenario: System auth and user auth return the same gateway URL
33+
Given I have a valid user token
34+
When I call get_system_auth
35+
And I call get_user_auth with the user token
36+
Then both gateway URLs should match
37+
38+
Scenario: Get user auth fails when user token is empty
39+
When I call get_user_auth with an empty user token
40+
Then the operation should fail with AgentGatewaySDKError
41+
And the error message should mention "user_token is required"
42+
43+
Scenario: List MCP tools returns a non-empty list of tools
44+
When I call list_mcp_tools
45+
Then the result should be a list of MCPTool
46+
And the list should be non-empty
47+
And each tool should have a non-empty name
48+
And each tool should have a non-empty url
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Pytest configuration and fixtures for Agent Gateway integration tests."""
2+
3+
from pathlib import Path
4+
5+
import pytest
6+
from dotenv import load_dotenv
7+
8+
from sap_cloud_sdk.agentgateway import create_client, AgentGatewayClient
9+
10+
11+
def _setup_cloud_mode():
12+
"""Load environment variables from .env_integration_tests if present."""
13+
env_file = Path(__file__).parents[3] / ".env_integration_tests"
14+
if env_file.exists():
15+
load_dotenv(env_file)
16+
17+
18+
@pytest.fixture(scope="session")
19+
def agw_client() -> AgentGatewayClient:
20+
"""Create an AgentGatewayClient from environment variables."""
21+
_setup_cloud_mode()
22+
23+
try:
24+
return create_client(tenant_subdomain="731465182")
25+
except Exception as e:
26+
pytest.fail(f"Failed to create Agent Gateway client for integration tests: {e}")
27+
28+
29+
# Configure pytest markers for integration tests
30+
def pytest_configure(config):
31+
"""Configure pytest markers."""
32+
config.addinivalue_line(
33+
"markers",
34+
"integration: mark test as integration test"
35+
)
36+
37+
38+
def pytest_collection_modifyitems(config, items):
39+
"""Automatically mark integration tests."""
40+
for item in items:
41+
if "integration" in str(item.fspath):
42+
item.add_marker(pytest.mark.integration)

0 commit comments

Comments
 (0)