102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
package config
|
||
|
||
import (
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
// What counts as a LOCAL model alias, and where that is demanded (ADR-034, ADR-035 review).
|
||
// A private transcript may be sent to a local model and to nothing else; the check is a
|
||
// guard against a misconfiguration or a crafted alias, so it must be strict about shape,
|
||
// not just about a prefix.
|
||
|
||
func TestIsLocalModel_AcceptsRealLocalAliasesAndNothingShapedLikeAnEscape(t *testing.T) {
|
||
tests := []struct {
|
||
alias string
|
||
want bool
|
||
}{
|
||
{"koala/phi4-mini", true},
|
||
{"iguana/gemma4-26b", true},
|
||
{"iguana/gemma4-31b-think", true},
|
||
{"koala/qwen36-35b-a3b", true},
|
||
{"iguana/kb-whisper", true},
|
||
{"iguana/hf.co-model_v1:q4", true},
|
||
{"", false},
|
||
{"koala/", false},
|
||
{"iguana/", false},
|
||
{"gemma4-26b", false},
|
||
{"berget/mistral-small", false},
|
||
{"berget/koala/x", false},
|
||
{"xkoala/x", false},
|
||
{"Koala/x", false},
|
||
{" koala/x", false},
|
||
{"koala/x ", false},
|
||
{"koala/x y", false},
|
||
{"koala/x\n", false},
|
||
{"koala/../berget/kb", false},
|
||
{"koala//berget/mistral-small", false},
|
||
{"koala/x/y", false},
|
||
{"koala/x?host=berget", false},
|
||
{"koala/x#frag", false},
|
||
{"koala/x@evil", false},
|
||
{"koalа/x", false}, // Cyrillic а
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.alias, func(t *testing.T) {
|
||
if got := IsLocalModel(tt.alias); got != tt.want {
|
||
t.Errorf("IsLocalModel(%q) = %v, want %v", tt.alias, got, tt.want)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestLoad_UploadChatModelMustBeLocalBecauseTheWholeTranscriptIsSentToIt(t *testing.T) {
|
||
for _, alias := range []string{"berget/mistral-small", "gemini/gemini-2.5-pro", "gemma4-26b", "koala/../berget/kb"} {
|
||
t.Run(alias, func(t *testing.T) {
|
||
clearUploadEnv(t)
|
||
setEnv(t, map[string]string{"TAPIR_UPLOAD_CHAT_MODEL": alias})
|
||
|
||
if _, err := Load(); err == nil {
|
||
t.Errorf("Load accepted TAPIR_UPLOAD_CHAT_MODEL=%q: a private transcript of up to 90,000 characters would be sent to it", alias)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestLoad_ALocalUploadChatModelIsAccepted(t *testing.T) {
|
||
clearUploadEnv(t)
|
||
setEnv(t, map[string]string{"TAPIR_UPLOAD_CHAT_MODEL": "iguana/gemma4-31b"})
|
||
|
||
cfg, err := Load()
|
||
if err != nil {
|
||
t.Fatalf("Load: %v", err)
|
||
}
|
||
if cfg.UploadChatModel != "iguana/gemma4-31b" {
|
||
t.Errorf("UploadChatModel = %q", cfg.UploadChatModel)
|
||
}
|
||
}
|
||
|
||
func TestLoad_TheEngineTimeoutDefaultsToTwentyFiveMinutesAndMustBePositive(t *testing.T) {
|
||
clearUploadEnv(t)
|
||
cfg, err := Load()
|
||
if err != nil {
|
||
t.Fatalf("Load: %v", err)
|
||
}
|
||
if cfg.TranscribeEngineTimeout != 25*time.Minute {
|
||
t.Errorf("TranscribeEngineTimeout = %v, want 25m: a 90-minute recording takes about 8 minutes on kb-whisper", cfg.TranscribeEngineTimeout)
|
||
}
|
||
|
||
setEnv(t, map[string]string{"TAPIR_TRANSCRIBE_ENGINE_TIMEOUT": "7m"})
|
||
cfg, err = Load()
|
||
if err != nil || cfg.TranscribeEngineTimeout != 7*time.Minute {
|
||
t.Errorf("override: %v, %v", cfg.TranscribeEngineTimeout, err)
|
||
}
|
||
|
||
for _, bad := range []string{"0", "-1m", "soon"} {
|
||
setEnv(t, map[string]string{"TAPIR_TRANSCRIBE_ENGINE_TIMEOUT": bad})
|
||
if _, err := Load(); err == nil {
|
||
t.Errorf("Load accepted TAPIR_TRANSCRIBE_ENGINE_TIMEOUT=%q", bad)
|
||
}
|
||
}
|
||
}
|