Skip to content

Commit a19c629

Browse files
e2e: add Response API basic operations tests
Add E2E tests for Response API basic operations: - POST /v1/responses - Create a new response - GET /v1/responses/{id} - Retrieve a response - DELETE /v1/responses/{id} - Delete a response - GET /v1/responses/{id}/input_items - List input items Signed-off-by: Jintao Zhang <[email protected]>
1 parent 1d1439a commit a19c629

File tree

4 files changed

+773
-0
lines changed

4 files changed

+773
-0
lines changed

e2e/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The framework follows a **separation of concerns** design:
1818
- **istio**: Tests Semantic Router with Istio service mesh integration
1919
- **production-stack**: Tests vLLM Production Stack configurations
2020
- **llm-d**: Tests Semantic Router with LLM-D distributed inference
21+
- **response-api**: Tests Response API endpoints (POST/GET/DELETE /v1/responses)
2122
- **dynamo**: Tests with Nvidia Dynamo (future)
2223

2324
## Directory Structure
@@ -82,6 +83,15 @@ The framework includes the following test cases (all in `e2e/testcases/`):
8283
| `pii-detection` | PII detection and blocking | 10 PII types, detection rate, block rate |
8384
| `jailbreak-detection` | Jailbreak attack detection | 10 attack types, detection rate, block rate |
8485

86+
### Response API Tests
87+
88+
| Test Case | Description | Metrics |
89+
|-----------|-------------|---------|
90+
| `response-api-create` | POST /v1/responses - Create a new response | Response ID validation, status check |
91+
| `response-api-get` | GET /v1/responses/{id} - Retrieve a response | Response retrieval, ID matching |
92+
| `response-api-delete` | DELETE /v1/responses/{id} - Delete a response | Deletion confirmation, 404 verification |
93+
| `response-api-input-items` | GET /v1/responses/{id}/input_items - List input items | Input items list, pagination |
94+
8595
### Signal-Decision Engine Tests
8696

8797
| Test Case | Description | Metrics |
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package responseapi
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"k8s.io/client-go/kubernetes"
9+
"k8s.io/client-go/tools/clientcmd"
10+
11+
"github.com/vllm-project/semantic-router/e2e/pkg/framework"
12+
"github.com/vllm-project/semantic-router/e2e/pkg/helm"
13+
"github.com/vllm-project/semantic-router/e2e/pkg/helpers"
14+
15+
// Import testcases package to register all test cases via their init() functions
16+
_ "github.com/vllm-project/semantic-router/e2e/testcases"
17+
)
18+
19+
// Profile implements the Response API test profile
20+
type Profile struct {
21+
verbose bool
22+
kubeConfig string
23+
}
24+
25+
// NewProfile creates a new Response API profile
26+
func NewProfile() *Profile {
27+
return &Profile{}
28+
}
29+
30+
// Name returns the profile name
31+
func (p *Profile) Name() string {
32+
return "response-api"
33+
}
34+
35+
// Description returns the profile description
36+
func (p *Profile) Description() string {
37+
return "Tests Response API endpoints (POST/GET/DELETE /v1/responses)"
38+
}
39+
40+
// Setup deploys all required components for Response API testing
41+
func (p *Profile) Setup(ctx context.Context, opts *framework.SetupOptions) error {
42+
p.verbose = opts.Verbose
43+
p.kubeConfig = opts.KubeConfig
44+
p.log("Setting up Response API test environment")
45+
46+
deployer := helm.NewDeployer(opts.KubeConfig, opts.Verbose)
47+
48+
// Step 1: Deploy Semantic Router with Response API enabled
49+
p.log("Step 1/3: Deploying Semantic Router with Response API")
50+
if err := p.deploySemanticRouter(ctx, deployer, opts); err != nil {
51+
return fmt.Errorf("failed to deploy semantic router: %w", err)
52+
}
53+
54+
// Step 2: Deploy Envoy Gateway
55+
p.log("Step 2/3: Deploying Envoy Gateway")
56+
if err := p.deployEnvoyGateway(ctx, deployer); err != nil {
57+
return fmt.Errorf("failed to deploy envoy gateway: %w", err)
58+
}
59+
60+
// Step 3: Verify all components are ready
61+
p.log("Step 3/3: Verifying all components are ready")
62+
if err := p.verifyEnvironment(ctx, opts); err != nil {
63+
return fmt.Errorf("failed to verify environment: %w", err)
64+
}
65+
66+
p.log("Response API test environment setup complete")
67+
return nil
68+
}
69+
70+
// Teardown cleans up all deployed resources
71+
func (p *Profile) Teardown(ctx context.Context, opts *framework.TeardownOptions) error {
72+
p.verbose = opts.Verbose
73+
p.log("Tearing down Response API test environment")
74+
75+
deployer := helm.NewDeployer(opts.KubeConfig, opts.Verbose)
76+
77+
p.log("Uninstalling Envoy Gateway")
78+
_ = deployer.Uninstall(ctx, "eg", "envoy-gateway-system")
79+
80+
p.log("Uninstalling Semantic Router")
81+
_ = deployer.Uninstall(ctx, "semantic-router", "vllm-semantic-router-system")
82+
83+
p.log("Response API test environment teardown complete")
84+
return nil
85+
}
86+
87+
// GetTestCases returns the list of test cases for this profile
88+
func (p *Profile) GetTestCases() []string {
89+
return []string{
90+
// Response API basic operations
91+
"response-api-create",
92+
"response-api-get",
93+
"response-api-delete",
94+
"response-api-input-items",
95+
}
96+
}
97+
98+
// GetServiceConfig returns the service configuration for accessing the deployed service
99+
func (p *Profile) GetServiceConfig() framework.ServiceConfig {
100+
return framework.ServiceConfig{
101+
LabelSelector: "gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=semantic-router",
102+
Namespace: "envoy-gateway-system",
103+
PortMapping: "8080:80",
104+
}
105+
}
106+
107+
func (p *Profile) deploySemanticRouter(ctx context.Context, deployer *helm.Deployer, opts *framework.SetupOptions) error {
108+
imageTag := opts.ImageTag
109+
if imageTag == "" {
110+
imageTag = "latest"
111+
}
112+
113+
return deployer.Install(ctx, helm.InstallOptions{
114+
ReleaseName: "semantic-router",
115+
Chart: "deploy/helm/semantic-router",
116+
Namespace: "vllm-semantic-router-system",
117+
ValuesFiles: []string{"e2e/profiles/response-api/values.yaml"},
118+
Set: map[string]string{
119+
"image.repository": "ghcr.io/vllm-project/semantic-router/extproc",
120+
"image.tag": imageTag,
121+
},
122+
Wait: true,
123+
Timeout: "300s",
124+
})
125+
}
126+
127+
func (p *Profile) deployEnvoyGateway(ctx context.Context, deployer *helm.Deployer) error {
128+
return deployer.Install(ctx, helm.InstallOptions{
129+
ReleaseName: "eg",
130+
Chart: "oci://docker.io/envoyproxy/gateway-helm",
131+
Namespace: "envoy-gateway-system",
132+
Wait: true,
133+
Timeout: "300s",
134+
})
135+
}
136+
137+
func (p *Profile) verifyEnvironment(ctx context.Context, opts *framework.SetupOptions) error {
138+
config, err := clientcmd.BuildConfigFromFlags("", opts.KubeConfig)
139+
if err != nil {
140+
return fmt.Errorf("failed to build kubeconfig: %w", err)
141+
}
142+
143+
client, err := kubernetes.NewForConfig(config)
144+
if err != nil {
145+
return fmt.Errorf("failed to create kubernetes client: %w", err)
146+
}
147+
148+
// Wait for semantic router deployment
149+
p.log("Waiting for Semantic Router deployment...")
150+
if err := p.waitForDeployment(ctx, client, "vllm-semantic-router-system", "semantic-router"); err != nil {
151+
return fmt.Errorf("semantic router deployment not ready: %w", err)
152+
}
153+
154+
p.log("All components are ready")
155+
return nil
156+
}
157+
158+
func (p *Profile) waitForDeployment(ctx context.Context, client *kubernetes.Clientset, namespace, name string) error {
159+
timeout := 5 * time.Minute
160+
interval := 5 * time.Second
161+
deadline := time.Now().Add(timeout)
162+
163+
for time.Now().Before(deadline) {
164+
if err := helpers.CheckDeployment(ctx, client, namespace, name, p.verbose); err == nil {
165+
return nil
166+
}
167+
time.Sleep(interval)
168+
}
169+
170+
return fmt.Errorf("timeout waiting for deployment %s/%s", namespace, name)
171+
}
172+
173+
func (p *Profile) log(msg string) {
174+
if p.verbose {
175+
fmt.Printf("[response-api] %s\n", msg)
176+
}
177+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Response API E2E Test Profile Values
2+
# This configuration enables Response API for testing
3+
4+
replicaCount: 1
5+
6+
image:
7+
repository: ghcr.io/vllm-project/semantic-router/extproc
8+
tag: latest
9+
pullPolicy: IfNotPresent
10+
11+
# Response API Configuration
12+
responseApi:
13+
enabled: true
14+
storeBackend: "memory"
15+
ttlSeconds: 86400
16+
maxResponses: 1000
17+
18+
# Semantic Cache (required for some tests)
19+
semanticCache:
20+
enabled: true
21+
backendType: "memory"
22+
similarityThreshold: 0.8
23+
maxEntries: 1000
24+
ttlSeconds: 3600
25+
26+
# vLLM Endpoints - use mock backend for testing
27+
vllmEndpoints:
28+
- name: "test-endpoint"
29+
address: "mock-vllm"
30+
port: 8000
31+
weight: 1
32+
33+
# Model configuration
34+
modelConfig:
35+
"MoM":
36+
useReasoning: false
37+
preferredEndpoints: ["test-endpoint"]
38+
39+
# Minimal classifier configuration
40+
classifier:
41+
categoryModel:
42+
modelId: "models/all-MiniLM-L12-v2"
43+
threshold: 0.6
44+
useCpu: true
45+
46+
# Categories
47+
categories:
48+
- name: other
49+
description: "General knowledge and miscellaneous topics"
50+
51+
# Strategy
52+
strategy: "priority"
53+
54+
# Decisions
55+
decisions:
56+
- name: "default_decision"
57+
description: "Default catch-all decision"
58+
priority: 1
59+
rules:
60+
operator: "OR"
61+
conditions:
62+
- type: "domain"
63+
name: "other"
64+
modelRefs:
65+
- model: "MoM"
66+
useReasoning: false
67+
68+
defaultModel: "MoM"
69+
70+
# Service configuration
71+
service:
72+
type: ClusterIP
73+
port: 8080
74+
75+
# Resources
76+
resources:
77+
limits:
78+
cpu: 500m
79+
memory: 512Mi
80+
requests:
81+
cpu: 100m
82+
memory: 128Mi

0 commit comments

Comments
 (0)