Files
HomeAgent/internal/lua/vm_test.go
root f0dacef281 lua: 吸收 llmsproxy 适配器高级特性(worker 池/静态预提取/动态签名钩子)
- 适配器 worker 池化:单 LState+全局锁(串行瓶颈)→ 每 adapter 一个 gopher-lua
  LState 池,按使用该 adapter 的源并发上限求和配置池大小,并发 transform 互不阻塞
- staticInfo 预提取:name/version/endpoint/headers 加载期编译缓存,Endpoint/Headers
  读缓存不占 worker;加载即预编译首个 worker
- build_headers 动态钩子 + hmac/sha256/base64/tohex 全局:签名型上游(kimicode 等)可接入
- provider applyAdapterHeaders 接入动态头(url/method/body/api_key/timestamp/source 元数据),
  未定义时回落静态 headers,缺省补 Authorization
- LLMSource.MaxConcurrent + core.llm.sources.<name>.max_concurrent,注册时汇总
  VM.ConfigureConcurrency
- 新增 Lua VM 测试(load/transform/build_headers/并发)

验证: go test ./... 27 包 0 失败;Windows 交叉编译通过;部署后 9 adapter 全部预加载
2026-08-10 11:29:57 +08:00

137 lines
3.2 KiB
Go

package lua
import (
"strings"
"sync"
"testing"
)
func TestVMLoadAndTransform(t *testing.T) {
vm := NewVM(t.TempDir())
if err := vm.Start(); err != nil {
t.Fatalf("start vm: %v", err)
}
defer vm.Stop()
out, err := vm.CallTransformRequest("openai", `{"model":"x"}`)
if err != nil {
t.Fatalf("transform_request: %v", err)
}
if !strings.Contains(out, `"model":"x"`) {
t.Fatalf("unexpected output: %s", out)
}
ep := vm.GetAdapterEndpoint("openai")
if ep == "" {
t.Fatal("openai endpoint empty")
}
hdrs := vm.GetAdapterHeaders("openai")
if hdrs == nil {
t.Fatal("openai headers nil")
}
}
func TestVMLoadCustomAdapter(t *testing.T) {
vm := NewVM(t.TempDir())
if err := vm.Start(); err != nil {
t.Fatalf("start vm: %v", err)
}
defer vm.Stop()
code := `
local adapter = {}
adapter.name = "testa"
adapter.version = "1.0"
adapter.endpoint = "/x"
adapter.headers = { ["X-A"] = "1" }
function adapter.transform_request(raw) return "REQ" end
function adapter.build_headers(meta) return { ["X-Key"] = "k" } end
function adapter.transform_response(raw) return "RESP" end
function adapter.transform_stream_chunk(raw) return "CHUNK" end
return adapter
`
if err := vm.LoadAdapterSource("testa", code); err != nil {
t.Fatalf("load adapter: %v", err)
}
if out, err := vm.CallTransformRequest("testa", "x"); err != nil || out != "REQ" {
t.Fatalf("req=%q err=%v", out, err)
}
if out, err := vm.CallTransformResponse("testa", "x"); err != nil || out != "RESP" {
t.Fatalf("resp=%q err=%v", out, err)
}
if out, err := vm.CallTransformStreamChunk("testa", "x"); err != nil || out != "CHUNK" {
t.Fatalf("chunk=%q err=%v", out, err)
}
meta := map[string]interface{}{"url": "http://x", "api_key": "k1"}
hdrs, err := vm.BuildHeaders("testa", meta)
if err != nil {
t.Fatalf("build_headers: %v", err)
}
if hdrs["X-Key"] != "k" {
t.Fatalf("missing dynamic header: %v", hdrs)
}
if ep := vm.GetAdapterEndpoint("testa"); ep != "/x" {
t.Fatalf("endpoint=%q", ep)
}
if st := vm.GetAdapterHeaders("testa"); st["X-A"] != "1" {
t.Fatalf("static headers=%v", st)
}
}
func TestVMLoadStaticHeaderFallback(t *testing.T) {
vm := NewVM(t.TempDir())
if err := vm.Start(); err != nil {
t.Fatalf("start vm: %v", err)
}
defer vm.Stop()
code := `
local adapter = {}
adapter.name = "statics"
adapter.headers = { ["X-S"] = "s" }
function adapter.transform_request(raw) return raw end
return adapter
`
if err := vm.LoadAdapterSource("statics", code); err != nil {
t.Fatalf("load: %v", err)
}
hdrs, err := vm.BuildHeaders("statics", nil)
if err != nil {
t.Fatalf("build_headers: %v", err)
}
if hdrs["X-S"] != "s" {
t.Fatalf("expected static fallback, got %v", hdrs)
}
}
func TestVMConcurrentCalls(t *testing.T) {
vm := NewVM(t.TempDir())
if err := vm.Start(); err != nil {
t.Fatalf("start vm: %v", err)
}
defer vm.Stop()
var wg sync.WaitGroup
errs := make(chan error, 40)
for i := 0; i < 20; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 10; j++ {
_, err := vm.CallTransformRequest("openai", `{"model":"x"}`)
if err != nil {
errs <- err
return
}
}
}()
}
wg.Wait()
close(errs)
for err := range errs {
t.Fatalf("concurrent call: %v", err)
}
}