win 21325afb33
Some checks failed
CI / test (push) Failing after 10s
CI / frontend (push) Failing after 8s
CI / golangci-lint (push) Failing after 5s
Security Scan / backend-security (push) Failing after 5s
Security Scan / frontend-security (push) Failing after 4s
feat(windsurf): 补全ops日志记录与endpoint派生,对齐其他平台
- windsurf_gateway_service: 添加上游延迟/TTFT/错误上下文记录
- endpoint: DeriveUpstreamEndpoint 添加 PlatformWindsurf 分支
- ops_error_logger: guessPlatformFromPath 添加 /windsurf/ 识别
2026-04-23 20:46:27 +08:00

303 lines
7.4 KiB
Go

package windsurf
import (
"fmt"
"testing"
)
func TestProxyKey(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{"empty string", "", "default"},
{"whitespace only", " ", "default"},
{"simple http proxy", "http://1.2.3.4:8080", "px_1_2_3_4_8080"},
{"https proxy", "https://proxy.example.com:3128", "px_proxy_example_com_3128"},
{"socks5 proxy", "socks5://10.0.0.1:1080", "px_10_0_0_1_1080"},
{"proxy with auth", "http://user:pass@1.2.3.4:8080", "px_1_2_3_4_8080_user"},
{"different auth same host", "http://other:secret@1.2.3.4:8080", "px_1_2_3_4_8080_other"},
{"no port", "http://proxy.local", "px_proxy_local"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := proxyKey(tt.input)
if got != tt.expected {
t.Errorf("proxyKey(%q) = %q, want %q", tt.input, got, tt.expected)
}
})
}
}
func TestProxyKeyDifferentAuthGetsDifferentKey(t *testing.T) {
k1 := proxyKey("http://alice:pw1@host:8080")
k2 := proxyKey("http://bob:pw2@host:8080")
if k1 == k2 {
t.Errorf("different credentials on same host should produce different keys: %q vs %q", k1, k2)
}
}
func TestRedactProxyURL(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"empty", "", "none"},
{"no auth", "http://1.2.3.4:8080", "http://1.2.3.4:8080"},
{"with auth stripped", "http://user:secret@1.2.3.4:8080", "http://1.2.3.4:8080"},
{"invalid url", "://bad", "<invalid>"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := redactProxyURL(tt.input)
if got != tt.want {
t.Errorf("redactProxyURL(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}
func TestIsPortInUse(t *testing.T) {
if isPortInUse(59999) {
t.Skip("port 59999 unexpectedly in use")
}
}
func TestWriteVarint(t *testing.T) {
tests := []struct {
val uint64
expect []byte
}{
{0, []byte{0}},
{1, []byte{1}},
{127, []byte{127}},
{128, []byte{0x80, 0x01}},
{300, []byte{0xAC, 0x02}},
}
for _, tt := range tests {
got := writeVarint(tt.val)
if len(got) != len(tt.expect) {
t.Errorf("writeVarint(%d) len=%d, want %d", tt.val, len(got), len(tt.expect))
continue
}
for i := range got {
if got[i] != tt.expect[i] {
t.Errorf("writeVarint(%d)[%d] = 0x%02x, want 0x%02x", tt.val, i, got[i], tt.expect[i])
}
}
}
}
func TestReadVarintRoundtrip(t *testing.T) {
values := []uint64{0, 1, 127, 128, 300, 16384, 1<<32 - 1}
for _, v := range values {
encoded := writeVarint(v)
decoded, pos, ok := ReadVarint(encoded, 0)
if !ok {
t.Errorf("ReadVarint failed for %d", v)
continue
}
if decoded != v {
t.Errorf("ReadVarint roundtrip: got %d, want %d", decoded, v)
}
if pos != len(encoded) {
t.Errorf("ReadVarint pos=%d, want %d", pos, len(encoded))
}
}
}
func TestEncodeStringField(t *testing.T) {
data := encodeStringField(1, "hello")
tag, pos, ok := ReadVarint(data, 0)
if !ok || tag != (1<<3|2) {
t.Fatalf("bad tag: %d ok=%v", tag, ok)
}
length, pos, ok := ReadVarint(data, pos)
if !ok || length != 5 {
t.Fatalf("bad length: %d ok=%v", length, ok)
}
if string(data[pos:pos+int(length)]) != "hello" {
t.Fatalf("payload mismatch")
}
}
func TestEncodeVarintField(t *testing.T) {
data := encodeVarintField(3, 42)
tag, pos, ok := ReadVarint(data, 0)
if !ok || tag != (3<<3|0) {
t.Fatalf("bad tag: %d ok=%v", tag, ok)
}
val, _, ok := ReadVarint(data, pos)
if !ok || val != 42 {
t.Fatalf("bad value: %d ok=%v", val, ok)
}
}
func TestParseStringField1(t *testing.T) {
data := encodeStringField(1, "cascade-123")
got, err := parseStringField1(data)
if err != nil {
t.Fatal(err)
}
if got != "cascade-123" {
t.Fatalf("got %q, want %q", got, "cascade-123")
}
}
func TestParseStringField1WithOtherFields(t *testing.T) {
var data []byte
data = append(data, encodeVarintField(2, 99)...)
data = append(data, encodeStringField(1, "target")...)
data = append(data, encodeStringField(3, "noise")...)
got, err := parseStringField1(data)
if err != nil {
t.Fatal(err)
}
if got != "target" {
t.Fatalf("got %q, want %q", got, "target")
}
}
func TestParseVarintField2(t *testing.T) {
var data []byte
data = append(data, encodeVarintField(1, 10)...)
data = append(data, encodeVarintField(2, 42)...)
got, err := parseVarintField2(data)
if err != nil {
t.Fatal(err)
}
if got != 42 {
t.Fatalf("got %d, want 42", got)
}
}
func TestResolveModelEnum(t *testing.T) {
if v := resolveModelEnum("MODEL_CLAUDE_4_SONNET"); v != 281 {
t.Errorf("got %d, want 281", v)
}
if v := resolveModelEnum("NONEXISTENT"); v != 0 {
t.Errorf("got %d, want 0", v)
}
}
func TestIsPanelStateNotFound(t *testing.T) {
tests := []struct {
msg string
want bool
}{
{"gRPC status 5: panel state not found for session abc", true},
{"NOT_FOUND: panel xyz is missing", true},
{"connection refused", false},
{"", false},
}
for _, tt := range tests {
var err error
if tt.msg != "" {
err = fmt.Errorf("%s", tt.msg)
}
got := isPanelStateNotFound(err)
if got != tt.want {
t.Errorf("isPanelStateNotFound(%q) = %v, want %v", tt.msg, got, tt.want)
}
}
}
func TestGenerateUUID(t *testing.T) {
u := generateUUID()
if len(u) != 36 {
t.Fatalf("UUID length = %d, want 36", len(u))
}
if u[8] != '-' || u[13] != '-' || u[18] != '-' || u[23] != '-' {
t.Fatalf("UUID format wrong: %s", u)
}
if u[14] != '4' {
t.Fatalf("UUID version not 4: %s", u)
}
u2 := generateUUID()
if u == u2 {
t.Fatal("two UUIDs should not be equal")
}
}
func TestBuildMetadata(t *testing.T) {
meta := buildMetadata("test-token-123", "session-abc")
got, err := parseStringField1(meta)
if err != nil {
t.Fatal(err)
}
if got != AppName {
t.Errorf("field 1 (ide_name) = %q, want %q", got, AppName)
}
}
func TestBuildCascadeConfig(t *testing.T) {
cfg := buildCascadeConfig("MODEL_CLAUDE_4_SONNET", 281, "")
if len(cfg) == 0 {
t.Fatal("buildCascadeConfig returned empty")
}
}
func TestStripGRPCFrame(t *testing.T) {
payload := []byte("hello world")
frame := make([]byte, 5+len(payload))
frame[0] = 0
frame[1] = 0
frame[2] = 0
frame[3] = 0
frame[4] = byte(len(payload))
copy(frame[5:], payload)
got := stripGRPCFrame(frame)
if string(got) != "hello world" {
t.Fatalf("got %q, want %q", got, "hello world")
}
}
func TestStripGRPCFrameShortData(t *testing.T) {
got := stripGRPCFrame([]byte{0, 0})
if string(got) != string([]byte{0, 0}) {
t.Fatal("short data should be returned as-is")
}
}
func TestNewLSPoolDefaults(t *testing.T) {
pool := NewLSPool(LSPoolConfig{}, nil)
if pool.config.Binary == "" {
t.Error("default binary should not be empty")
}
if pool.config.BasePort != DefaultLSPort {
t.Errorf("default port = %d, want %d", pool.config.BasePort, DefaultLSPort)
}
if pool.config.CSRFToken != DefaultCSRF {
t.Errorf("default CSRF = %q, want %q", pool.config.CSRFToken, DefaultCSRF)
}
}
func TestLSPoolGetNonExistent(t *testing.T) {
pool := NewLSPool(LSPoolConfig{}, nil)
if e := pool.Get("http://nonexistent:9999"); e != nil {
t.Error("Get on empty pool should return nil")
}
}
func TestLSPoolStatus(t *testing.T) {
pool := NewLSPool(LSPoolConfig{}, nil)
s := pool.Status()
if s.Running {
t.Error("empty pool should not be running")
}
if len(s.Instances) != 0 {
t.Error("empty pool should have no instances")
}
}
func TestLSPoolShutdownEmpty(t *testing.T) {
pool := NewLSPool(LSPoolConfig{}, nil)
pool.Shutdown()
s := pool.Status()
if s.Running {
t.Error("shutdown pool should not be running")
}
}