一键导入
aigw-contrib-testing
Test hierarchy, go-vcr recording, testcontainers, func-e data plane tests, coverage thresholds, and anti-patterns for envoyproxy/ai-gateway
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Test hierarchy, go-vcr recording, testcontainers, func-e data plane tests, coverage thresholds, and anti-patterns for envoyproxy/ai-gateway
用 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-testing |
| description | Test hierarchy, go-vcr recording, testcontainers, func-e data plane tests, coverage thresholds, and anti-patterns for envoyproxy/ai-gateway |
| Level | Location | Command | K8s Required | Purpose |
|---|---|---|---|---|
| Unit | *_test.go (same package) | make test | No | Test individual functions and types |
| CEL validation | tests/crdcel/ | make test-crdcel | envtest | Test CRD validation rules |
| Controller | tests/controller/ | make test-controller | envtest | Test reconciler logic with fake K8s |
| Data plane | tests/data-plane/ | make test-data-plane | No | Test ExtProc with real Envoy (func-e) |
| E2E | tests/e2e/ | make test-e2e | kind cluster | Full stack: EG + AI Gateway + Envoy |
// 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.
package translators
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestTranslateRequest(t *testing.T) {
tests := []struct {
name string
input []byte
expOutput []byte
expErr string
}{
{
name: "valid chat completion",
input: []byte(`{"model":"gpt-4o","messages":[...]}`),
expOutput: []byte(`{"modelId":"anthropic.claude-v2",...}`),
},
{
name: "missing model field",
input: []byte(`{"messages":[...]}`),
expErr: "missing model",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
output, err := translateRequest(tc.input)
if tc.expErr != "" {
require.ErrorContains(t, err, tc.expErr)
return
}
require.NoError(t, err)
require.JSONEq(t, string(tc.expOutput), string(output))
})
}
}
require for fatal assertions (test cannot continue without this passing)assert for non-fatal assertions (test can still provide useful info)t.Context() — never context.Background() in testsexp prefix for expected values: expBody, expStatus, expPathname field and t.RunTestMain in every package for goroutine leak detection:func TestMain(m *testing.M) {
goleak.VerifyNone(m)
}
AI Gateway uses go-vcr to record real HTTP interactions with LLM providers and replay them in CI. This avoids flaky tests that depend on external APIs.
import "gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
func TestWithVCR(t *testing.T) {
r, err := recorder.New("testdata/fixtures/my-test")
require.NoError(t, err)
defer r.Stop()
client := &http.Client{Transport: r}
// Use client to make requests — responses are recorded
}
Delete the cassette file and re-run the test in record mode with real API credentials.
Used for tests that need real infrastructure (Redis, databases, etc.):
import "github.com/testcontainers/testcontainers-go"
func TestWithRedis(t *testing.T) {
ctx := t.Context()
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "redis:7",
ExposedPorts: []string{"6379/tcp"},
},
Started: true,
})
require.NoError(t, err)
defer container.Terminate(ctx)
// ...
}
Test CRD validation rules using envtest (real API server, no controllers):
// tests/crdcel/aigatewayroute_test.go
func TestAIGatewayRouteCELValidation(t *testing.T) {
// envtest is set up in TestMain
tests := []struct {
name string
route *aigv1a1.AIGatewayRoute
wantError bool
}{
{
name: "valid route",
route: &aigv1a1.AIGatewayRoute{
// ...valid spec
},
},
{
name: "invalid: missing parentRefs",
route: &aigv1a1.AIGatewayRoute{
// ...missing required field
},
wantError: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := k8sClient.Create(t.Context(), tc.route)
if tc.wantError {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
Test reconciler logic with envtest (real API server, your controllers running):
// tests/controller/ai_gateway_route_test.go
func TestAIGatewayRouteReconciler(t *testing.T) {
// Create test resources
route := &aigv1a1.AIGatewayRoute{...}
require.NoError(t, k8sClient.Create(t.Context(), route))
// Wait for reconciliation
require.Eventually(t, func() bool {
var result aigv1a1.AIGatewayRoute
err := k8sClient.Get(t.Context(), client.ObjectKeyFromObject(route), &result)
return err == nil && result.Status.Conditions != nil
}, 10*time.Second, 100*time.Millisecond)
}
Test ExtProc translation with a real Envoy binary — no Kubernetes needed:
func-e downloads and runs a real Envoy binary locally// tests/data-plane/translation_test.go
//go:build test_data_plane
func TestOpenAIToAWSBedrock(t *testing.T) {
// 1. Write filterapi.Config to temp file
// 2. Start ExtProc server reading that config
// 3. Start Envoy via func-e with ExtProc filter
// 4. Send OpenAI-format request through Envoy
// 5. Verify backend receives AWS Bedrock format
// 6. Verify response is translated back to OpenAI format
}
Data plane tests use build tag test_data_plane:
//go:build test_data_plane
| Scope | Threshold |
|---|---|
| Per file | 70% |
| Per package | 81% |
| Total | 86% |
| Patch (new/changed lines) | 80% |
Run coverage: make test-coverage
| Anti-Pattern | Fix |
|---|---|
Using encoding/json in tests | Use internal/json — still banned in test files |
Using context.Background() | Use t.Context() |
Missing goleak.VerifyNone(t) in TestMain | Add to every package |
time.Sleep in integration/e2e tests | Use require.Eventually or polling |
| Hardcoded API keys in test files | Use environment variables or go-vcr cassettes |
| Not testing streaming responses | Every translator needs SSE streaming tests |
| Not testing error cases | Add invalid input, missing fields, malformed JSON |
| Testing with real providers in CI | Use go-vcr cassettes for deterministic replay |
| Large test functions without subtests | Use table-driven t.Run for each case |
| Not cleaning up test resources | Use t.Cleanup() or defer |