Files
go-sip/internal/ai/asr_sdk_test.go
T

94 lines
4.0 KiB
Go

package ai
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/gorilla/websocket"
)
type currentASRWireCapture struct {
path, key, resourceID string
frame []byte
err error
}
func TestASRParametersReachDoubaoSDKWebSocket(t *testing.T) {
for _, tc := range []struct {
mode, resultType string
nonstream bool
}{
{"full_ai", "full", false},
{"asr_only", "single", true},
} {
t.Run(tc.mode, func(t *testing.T) {
captures := make(chan currentASRWireCapture, 1)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
conn, err := (&websocket.Upgrader{}).Upgrade(w, r, nil)
if err != nil {
captures <- currentASRWireCapture{err: err}
return
}
defer conn.Close()
_, frame, err := conn.ReadMessage()
captures <- currentASRWireCapture{path: r.URL.Path, key: r.Header.Get("X-Api-Key"), resourceID: r.Header.Get("X-Api-Resource-Id"), frame: frame, err: err}
}))
defer server.Close()
task, providers := currentFixture(t, tc.mode)
task = changeCurrentAgent(t, task, func(a map[string]any) {
a["asr"].(map[string]any)["params"] = map[string]any{"reqid": "ignored-params-reqid", "sequence": 99, "model_name": "ignored-params-model", "result_type": tc.resultType, "enable_nonstream": tc.nonstream, "unknown_flag": false, "nullable": nil, "opaque": "vendor-only", "large_number": json.Number("9007199254740993")}
})
asrProvider := providers["volcengine"]
asrProvider.WSEndpoint = "ws" + strings.TrimPrefix(server.URL, "http")
providers[asrProvider.Code] = asrProvider
bound, err := Bind(task, providers)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
if _, err := bound.Recognize(ctx, []byte{1, 0}); err == nil {
t.Fatal("disconnected mock ASR cannot pretend recognition completed")
}
select {
case got := <-captures:
if got.err != nil || got.path != "/api/v3/sauc/bigmodel" || got.key != asrProvider.Credential || got.resourceID != "volc.seedasr.sauc.duration" {
t.Fatalf("SDK ASR WebSocket endpoint/credential was changed: path=%q err=%v", got.path, got.err)
}
// Inspect the SDK-emitted JSON payload. No provider protocol is
// implemented by the application or by this mock responder.
start := bytes.IndexByte(got.frame, '{')
if start < 0 {
t.Fatal("SDK sent no ASR start JSON frame")
}
if !bytes.Contains(got.frame[start:], []byte(`"large_number":9007199254740993`)) {
t.Fatal("large integer changed")
}
var payload map[string]any
if err := json.Unmarshal(got.frame[start:], &payload); err != nil {
t.Fatalf("SDK ASR start JSON cannot be decoded: %v", err)
}
audio := payload["audio"].(map[string]any)
request := payload["request"].(map[string]any)
if request["model_name"] != bound.ASR.Model || request["reqid"] == "ignored-params-reqid" || request["reqid"] == "" || request["sequence"] != float64(1) {
t.Fatal("params overrode the ASR task model or session identity")
}
if string(bound.ASR.Params["model_name"]) != `"ignored-params-model"` || string(bound.ASR.Params["reqid"]) != `"ignored-params-reqid"` || string(bound.ASR.Params["sequence"]) != "99" {
t.Fatal("ASR request construction changed the original params")
}
if len(audio) != 4 || len(request) != 9 || audio["format"] != "pcm_s16le" || audio["sample_rate"] != float64(16000) || audio["channel"] != float64(1) || audio["bits"] != float64(16) || request["result_type"] != tc.resultType || request["enable_nonstream"] != tc.nonstream || request["unknown_flag"] != false || request["nullable"] != nil || request["opaque"] != "vendor-only" {
t.Fatalf("SDK ASR request omitted approved input/interim fields: audio=%v request=%v", audio, request)
}
case <-ctx.Done():
t.Fatal("SDK did not send an ASR start request to isolated mock")
}
})
}
}