Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ai-proxy e2e 支持通义千问非流式响应
Browse files Browse the repository at this point in the history
hanxiantao committed Jan 30, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent b79fa88 commit 8aa8fa1
Showing 3 changed files with 103 additions and 7 deletions.
23 changes: 23 additions & 0 deletions test/e2e/conformance/tests/go-wasm-ai-proxy.go
Original file line number Diff line number Diff line change
@@ -277,6 +277,29 @@ data: [DONE]
},
},
},
{
Meta: http.AssertionMeta{
TestCaseName: "qwen case 3: non-streaming request",
CompareTarget: http.CompareTargetResponse,
},
Request: http.AssertionRequest{
ActualRequest: http.Request{
Host: "dashscope.aliyuncs.com",
Path: "/v1/chat/completions",
Method: "POST",
ContentType: http.ContentTypeApplicationJson,
Body: []byte(`{"model":"gpt-3","messages":[{"role":"user","content":"你好,你是谁?"}],"stream":false}`),
},
},
Response: http.AssertionResponse{
ExpectedResponse: http.Response{
StatusCode: 200,
ContentType: http.ContentTypeApplicationJson,
JsonBodyIgnoreFields: []string{"created"},
Body: []byte(`{"id":"chatcmpl-llm-mock","choices":[{"index":0,"message":{"role":"assistant","content":"你好,你是谁?"},"finish_reason":"stop"}],"created":1738218357,"model":"qwen-turbo","object":"chat.completion","usage":{"prompt_tokens":9,"completion_tokens":1,"total_tokens":10}}`),
},
},
},
}
t.Run("WasmPlugins ai-proxy", func(t *testing.T) {
for _, testcase := range testcases {
33 changes: 32 additions & 1 deletion test/e2e/conformance/tests/go-wasm-ai-proxy.yaml
Original file line number Diff line number Diff line change
@@ -87,6 +87,25 @@ spec:
port:
number: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wasmplugin-ai-proxy-qwen
namespace: higress-conformance-ai-backend
spec:
ingressClassName: higress
rules:
- host: "dashscope.aliyuncs.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: llm-mock-service
port:
number: 3000
---
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
@@ -143,4 +162,16 @@ spec:
qwenEnableCompatible: true
ingress:
- higress-conformance-ai-backend/wasmplugin-ai-proxy-qwen-compatible-mode
url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/ai-proxy:1.0.0
- config:
provider:
apiTokens:
- fake_token
modelMapping:
'gpt-3': qwen-turbo
'gpt-35-turbo': qwen-plus
'gpt-4-*': qwen-max
'*': qwen-turbo
type: qwen
ingress:
- higress-conformance-ai-backend/wasmplugin-ai-proxy-qwen
url: file:///opt/plugins/wasm-go/extensions/ai-proxy/plugin.wasm
54 changes: 48 additions & 6 deletions test/e2e/conformance/utils/http/http.go
Original file line number Diff line number Diff line change
@@ -141,11 +141,12 @@ type ExpectedRequest struct {

// Response defines expected properties of a response from a backend.
type Response struct {
StatusCode int
Headers map[string]string
Body []byte
ContentType string
AbsentHeaders []string
StatusCode int
Headers map[string]string
Body []byte
JsonBodyIgnoreFields []string
ContentType string
AbsentHeaders []string
}

// requiredConsecutiveSuccesses is the number of requests that must succeed in a row
@@ -618,7 +619,7 @@ func CompareResponse(cRes *roundtripper.CapturedResponse, expected Assertion) er
return fmt.Errorf("failed to unmarshall CapturedResponse body %s, %s", string(cRes.Body), err.Error())
}

if !reflect.DeepEqual(eResBody, cResBody) {
if err := CompareJSONWithIgnoreFields(eResBody, cResBody, expected.Response.ExpectedResponse.JsonBodyIgnoreFields); err != nil {
return fmt.Errorf("expected %s body to be %s, got %s", cTyp, string(expected.Response.ExpectedResponse.Body), string(cRes.Body))
}
case ContentTypeFormUrlencoded:
@@ -665,6 +666,47 @@ func CompareResponse(cRes *roundtripper.CapturedResponse, expected Assertion) er
}
return nil
}

// CompareJSONWithIgnoreFields compares two JSON objects, ignoring specified fields
func CompareJSONWithIgnoreFields(eResBody, cResBody map[string]interface{}, ignoreFields []string) error {
for key, eVal := range eResBody {
if contains(ignoreFields, key) {
continue
}

cVal, exists := cResBody[key]
if !exists {
return fmt.Errorf("field %s exists in expected response but not in captured response", key)
}

if !reflect.DeepEqual(eVal, cVal) {
return fmt.Errorf("field %s mismatch: expected %v, got %v", key, eVal, cVal)
}
}

// Check if captured response has extra fields (excluding ignored fields)
for key := range cResBody {
if contains(ignoreFields, key) {
continue
}

if _, exists := eResBody[key]; !exists {
return fmt.Errorf("field %s exists in captured response but not in expected response", key)
}
}

return nil
}

func contains(slice []string, str string) bool {
for _, s := range slice {
if s == str {
return true
}
}
return false
}

func ParseFormUrlencodedBody(body []byte) (map[string][]string, error) {
ret := make(map[string][]string)
kvs, err := url.ParseQuery(string(body))

0 comments on commit 8aa8fa1

Please sign in to comment.