mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-11 23:40:28 -10:00
Summary: - Add Go model catalog metadata and registry filters for provider, capability, aliases, and reasoning effort. - Add tier-aware cost estimation and USD formatting helpers with normalized usage handling. - Cover model validation, catalog filtering, defensive cloning, pricing tiers, and Windows command-timeout CI behavior. Validation: - go test ./internal/config -run TestLoadProviderCommandTimeout -count=3 -v - go test ./... - bun run typecheck - bun test ./tests --timeout 15000 - bun run build - bun run smoke:build - bun run build:go - bun run smoke:go - ./zero --help - git diff --check
158 lines
4.2 KiB
Go
158 lines
4.2 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLoadProviderCommandSuccess(t *testing.T) {
|
|
command := writeCommand(t, commandScript{
|
|
Stdout: `{"name":"cmd","provider":"openai","apiKey":"sk-command","model":"gpt-command"}`,
|
|
})
|
|
|
|
cfg, err := LoadProviderCommand(command)
|
|
if err != nil {
|
|
t.Fatalf("LoadProviderCommand() error = %v", err)
|
|
}
|
|
|
|
if len(cfg.Providers) != 1 {
|
|
t.Fatalf("providers length = %d, want 1", len(cfg.Providers))
|
|
}
|
|
provider := cfg.Providers[0]
|
|
if provider.Name != "cmd" || provider.APIKey != "sk-command" || provider.Model != "gpt-command" {
|
|
t.Fatalf("provider = %#v, want command provider", provider)
|
|
}
|
|
}
|
|
|
|
func TestLoadProviderCommandFailureIncludesExitAndRedactsOutput(t *testing.T) {
|
|
command := writeCommand(t, commandScript{
|
|
Stderr: "failed with sk-command-secret",
|
|
ExitCode: 7,
|
|
})
|
|
|
|
_, err := LoadProviderCommand(command)
|
|
if err == nil {
|
|
t.Fatal("LoadProviderCommand() error = nil, want command failure")
|
|
}
|
|
if !strings.Contains(err.Error(), "provider command failed") || !strings.Contains(err.Error(), "exit status") {
|
|
t.Fatalf("error = %q, want command failure with exit status", err.Error())
|
|
}
|
|
if strings.Contains(err.Error(), "sk-command-secret") {
|
|
t.Fatalf("error leaked command secret: %q", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestLoadProviderCommandTimeout(t *testing.T) {
|
|
command := writeCommand(t, commandScript{SleepSeconds: 10})
|
|
|
|
start := time.Now()
|
|
_, err := LoadProviderCommand(command)
|
|
elapsed := time.Since(start)
|
|
if err == nil {
|
|
t.Fatal("LoadProviderCommand() error = nil, want timeout")
|
|
}
|
|
if !strings.Contains(err.Error(), "timed out after 5s") {
|
|
t.Fatalf("error = %q, want timeout", err.Error())
|
|
}
|
|
maxElapsed := 7 * time.Second
|
|
if runtime.GOOS == "windows" {
|
|
maxElapsed = 9 * time.Second
|
|
}
|
|
if elapsed > maxElapsed {
|
|
t.Fatalf("timeout returned after %s, want roughly 5s", elapsed)
|
|
}
|
|
}
|
|
|
|
func TestLoadProviderCommandInvalidJSON(t *testing.T) {
|
|
command := writeCommand(t, commandScript{Stdout: `{not-json`})
|
|
|
|
_, err := LoadProviderCommand(command)
|
|
if err == nil {
|
|
t.Fatal("LoadProviderCommand() error = nil, want JSON error")
|
|
}
|
|
if !strings.Contains(err.Error(), "invalid provider command JSON") {
|
|
t.Fatalf("error = %q, want invalid JSON", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestLoadProviderCommandMissingModel(t *testing.T) {
|
|
command := writeCommand(t, commandScript{
|
|
Stdout: `{"name":"cmd","provider":"openai","apiKey":"sk-command"}`,
|
|
})
|
|
|
|
_, err := LoadProviderCommand(command)
|
|
if err == nil {
|
|
t.Fatal("LoadProviderCommand() error = nil, want missing model")
|
|
}
|
|
if !strings.Contains(err.Error(), "provider cmd requires model") {
|
|
t.Fatalf("error = %q, want missing model", err.Error())
|
|
}
|
|
}
|
|
|
|
type commandScript struct {
|
|
Stdout string
|
|
Stderr string
|
|
ExitCode int
|
|
SleepSeconds int
|
|
}
|
|
|
|
func writeCommand(t *testing.T, script commandScript) string {
|
|
t.Helper()
|
|
|
|
dir := t.TempDir()
|
|
if runtime.GOOS == "windows" {
|
|
path := filepath.Join(dir, "provider.cmd")
|
|
lines := []string{"@echo off"}
|
|
if script.SleepSeconds > 0 {
|
|
lines = append(lines, "powershell -NoProfile -Command \"Start-Sleep -Seconds "+itoa(script.SleepSeconds)+"\"")
|
|
}
|
|
if script.Stdout != "" {
|
|
lines = append(lines, "echo "+script.Stdout)
|
|
}
|
|
if script.Stderr != "" {
|
|
lines = append(lines, "echo "+script.Stderr+" 1>&2")
|
|
}
|
|
lines = append(lines, "exit /b "+itoa(script.ExitCode))
|
|
if err := os.WriteFile(path, []byte(strings.Join(lines, "\r\n")), 0o700); err != nil {
|
|
t.Fatalf("write command: %v", err)
|
|
}
|
|
return path
|
|
}
|
|
|
|
path := filepath.Join(dir, "provider.sh")
|
|
lines := []string{"#!/bin/sh"}
|
|
if script.SleepSeconds > 0 {
|
|
lines = append(lines, "sleep "+itoa(script.SleepSeconds))
|
|
}
|
|
if script.Stdout != "" {
|
|
lines = append(lines, "printf '%s\\n' '"+script.Stdout+"'")
|
|
}
|
|
if script.Stderr != "" {
|
|
lines = append(lines, "printf '%s\\n' '"+script.Stderr+"' >&2")
|
|
}
|
|
lines = append(lines, "exit "+itoa(script.ExitCode))
|
|
if err := os.WriteFile(path, []byte(strings.Join(lines, "\n")), 0o700); err != nil {
|
|
t.Fatalf("write command: %v", err)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func itoa(value int) string {
|
|
if value == 0 {
|
|
return "0"
|
|
}
|
|
|
|
var digits [20]byte
|
|
index := len(digits)
|
|
for value > 0 {
|
|
index--
|
|
digits[index] = byte('0' + value%10)
|
|
value /= 10
|
|
}
|
|
return string(digits[index:])
|
|
}
|