ワンクリックで
aigw-contrib-e2e
Write end-to-end tests for envoyproxy/ai-gateway — kind cluster setup, test manifests, mock providers, streaming assertions
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Write end-to-end tests for envoyproxy/ai-gateway — kind cluster setup, test manifests, mock providers, streaming assertions
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Configure client-facing traffic policies -- timeouts, connection limits, TLS settings, HTTP behavior
Production-grade Envoy Gateway setup with comprehensive security, observability, high availability, and operational best practices
Integrate Envoy Gateway with Istio ambient mesh or Cilium for unified ingress and service mesh
Envoy Gateway version information, compatibility matrix, and upgrade readiness checks
Envoy AI Gateway contribution orchestrator — interviews you about your contribution and guides you through the correct workflow using contributor skills
Envoy Gateway contribution orchestrator — interviews you about your contribution and guides you through the correct workflow using contributor skills
| name | aigw-contrib-e2e |
| description | Write end-to-end tests for envoyproxy/ai-gateway — kind cluster setup, test manifests, mock providers, streaming assertions |
| arguments | [{"name":"Feature","description":"Feature to test (e.g., openai-bedrock-translation, model-routing, token-ratelimit)","required":true},{"name":"TestType","description":"Type of e2e test: basic, streaming, failover, auth","required":false}] |
Write end-to-end tests that run against a real Kubernetes cluster with Envoy Gateway and AI Gateway installed.
tests/e2e/
├── e2e_test.go # Test suite setup (kind cluster, EG, AI Gateway)
├── testdata/
│ ├── gateway.yaml # Shared Gateway resources
│ ├── *.yaml # Test-specific manifests
│ └── ...
├── ${feature}_test.go # Feature-specific tests
└── ...
kind installedhelm installedkubectl installedCreate tests/e2e/${feature}_test.go:
// Copyright Envoy AI Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.
//go:build test_e2e
package e2e
import (
"testing"
"github.com/stretchr/testify/require"
aigv1a1 "github.com/envoyproxy/ai-gateway/api/v1alpha1"
)
func Test${Feature}(t *testing.T) {
// 1. Apply test manifests
// 2. Wait for resources to be ready
// 3. Send test requests
// 4. Verify responses
// 5. Clean up
}
E2E tests use the test_e2e build tag:
//go:build test_e2e
Create manifests in tests/e2e/testdata/${feature}.yaml:
# Backend for mock provider
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: mock-${provider}
namespace: default
spec:
endpoints:
- fqdn:
hostname: mock-${provider}.default.svc.cluster.local
port: 8080
---
# AIServiceBackend
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIServiceBackend
metadata:
name: mock-${provider}
namespace: default
spec:
schema:
name: ${Schema} # OpenAI, Anthropic, AWSBedrock, etc.
backendRef:
name: mock-${provider}
kind: Backend
group: gateway.envoyproxy.io
---
# AIGatewayRoute
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIGatewayRoute
metadata:
name: test-${feature}-route
namespace: default
spec:
parentRefs:
- name: test-gateway
kind: Gateway
group: gateway.networking.k8s.io
rules:
- backendRefs:
- name: mock-${provider}
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: BackendSecurityPolicy
metadata:
name: mock-${provider}-auth
namespace: default
spec:
targetRefs:
- group: aigateway.envoyproxy.io
kind: AIServiceBackend
name: mock-${provider}
type: APIKey
apiKey:
secretRef:
name: mock-api-key
namespace: default
---
apiVersion: v1
kind: Secret
metadata:
name: mock-api-key
namespace: default
type: Opaque
stringData:
apiKey: "test-key-for-e2e"
E2E tests use mock HTTP servers that simulate LLM provider APIs:
func startMockProvider(t *testing.T) {
mux := http.NewServeMux()
mux.HandleFunc("/v1/chat/completions", func(w http.ResponseWriter, r *http.Request) {
// Verify request format matches expected schema
body, _ := io.ReadAll(r.Body)
// ... validate request body
// Return mock response
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{
"id": "chatcmpl-test",
"object": "chat.completion",
"choices": [{
"message": {"role": "assistant", "content": "Hello from mock"},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 10, "completion_tokens": 5}
}`))
})
// Deploy as a K8s Service in the test namespace
}
mux.HandleFunc("/v1/chat/completions", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
flusher := w.(http.Flusher)
chunks := []string{
`{"id":"chatcmpl-test","choices":[{"delta":{"content":"Hello"}}]}`,
`{"id":"chatcmpl-test","choices":[{"delta":{"content":" world"}}]}`,
}
for _, chunk := range chunks {
fmt.Fprintf(w, "data: %s\n\n", chunk)
flusher.Flush()
}
fmt.Fprint(w, "data: [DONE]\n\n")
flusher.Flush()
})
func Test${Feature}_BasicRequest(t *testing.T) {
// Apply manifests
applyManifests(t, "testdata/${feature}.yaml")
// Wait for route to be ready
waitForRoute(t, "test-${feature}-route")
// Send request
resp := sendChatCompletion(t, gatewayURL, map[string]interface{}{
"model": "test-model",
"messages": []map[string]string{{"role": "user", "content": "test"}},
})
require.Equal(t, 200, resp.StatusCode)
// Verify response body
}
func Test${Feature}_Streaming(t *testing.T) {
resp := sendChatCompletion(t, gatewayURL, map[string]interface{}{
"model": "test-model",
"stream": true,
"messages": []map[string]string{{"role": "user", "content": "test"}},
})
require.Equal(t, 200, resp.StatusCode)
require.Equal(t, "text/event-stream", resp.Header.Get("Content-Type"))
// Read SSE events
events := readSSEEvents(t, resp.Body)
require.Greater(t, len(events), 0)
// Verify last event is [DONE]
require.Equal(t, "[DONE]", events[len(events)-1])
}
func Test${Feature}_ModelRouting(t *testing.T) {
// Request with model A → should route to backend A
respA := sendChatCompletion(t, gatewayURL, map[string]interface{}{
"model": "gpt-4o",
"messages": []map[string]string{{"role": "user", "content": "test"}},
})
// Verify routed to correct backend
// Request with model B → should route to backend B
respB := sendChatCompletion(t, gatewayURL, map[string]interface{}{
"model": "claude-3-5-sonnet",
"messages": []map[string]string{{"role": "user", "content": "test"}},
})
// Verify routed to correct backend
}
make test-e2e
This sets up a kind cluster, installs EG + AI Gateway, runs all e2e tests, and tears down.
| Anti-Pattern | Fix |
|---|---|
time.Sleep for waiting | Use require.Eventually with polling |
| Hardcoded timeouts | Use configurable timeouts with generous defaults |
| Not cleaning up resources | Use t.Cleanup() to remove test manifests |
| Testing against real providers | Use mock HTTP servers deployed in-cluster |
| Not testing streaming | Always test both streaming and non-streaming paths |
| Missing error response tests | Test 4xx/5xx responses from backends |
| Not verifying request body at backend | Mock server should validate incoming request format |
//go:build test_e2e tag and license headertests/e2e/testdata/require.Eventually for async operations (not time.Sleep)t.Cleanup for resource teardownmake test-e2e passes