sync: migrate ai-operator to Gitea (2026-08-10)
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadConfigAllowsOptionalEmptyValues(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "app.env")
|
||||
content := `APP_ENV=dev
|
||||
LOG_LEVEL=debug
|
||||
ASTERISK_ARI_URL=http://127.0.0.1:8088/ari
|
||||
ASTERISK_ARI_WS_URL=ws://127.0.0.1:8088/ari/events
|
||||
ASTERISK_ARI_USER=ai_operator
|
||||
ASTERISK_ARI_PASSWORD=test-password
|
||||
ASTERISK_ARI_APP=ai-operator
|
||||
ASTERISK_MEDIA_MODE=chan_websocket
|
||||
ASTERISK_MEDIA_CODEC=slin16
|
||||
OPENAI_API_KEY=
|
||||
OPENAI_REALTIME_MODEL=
|
||||
DATABASE_URL=
|
||||
`
|
||||
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg, resolved, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Load() error = %v", err)
|
||||
}
|
||||
if resolved != path {
|
||||
t.Fatalf("resolved path = %q, want %q", resolved, path)
|
||||
}
|
||||
if cfg.OpenAI.APIKey != "" {
|
||||
t.Fatal("OpenAI API key should be optional and empty")
|
||||
}
|
||||
if cfg.Database.URL != "" {
|
||||
t.Fatal("Database URL should be optional and empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigRequiresCriticalFields(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "bad.env")
|
||||
if err := os.WriteFile(path, []byte("APP_ENV=dev\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := Load(path); err == nil {
|
||||
t.Fatal("Load() error = nil, want validation error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMasking(t *testing.T) {
|
||||
if got := MaskSecret("password"); got != "***MASKED***" {
|
||||
t.Fatalf("MaskSecret() = %q", got)
|
||||
}
|
||||
if got := MaskOpenAIKey(""); got != "***EMPTY***" {
|
||||
t.Fatalf("MaskOpenAIKey(empty) = %q", got)
|
||||
}
|
||||
if got := MaskOpenAIKey("sk-test"); got != "sk-***MASKED***" {
|
||||
t.Fatalf("MaskOpenAIKey(non-empty) = %q", got)
|
||||
}
|
||||
got := MaskURLCredentials("postgres://user:pass@localhost/db")
|
||||
want := "postgres://%2A%2A%2AMASKED%2A%2A%2A:%2A%2A%2AMASKED%2A%2A%2A@localhost/db"
|
||||
if got != want {
|
||||
t.Fatalf("MaskURLCredentials() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialogueConfigDefaults(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "dialogue.env")
|
||||
content := `APP_ENV=dev
|
||||
LOG_LEVEL=debug
|
||||
ASTERISK_ARI_URL=http://127.0.0.1:8088/ari
|
||||
ASTERISK_ARI_WS_URL=ws://127.0.0.1:8088/ari/events
|
||||
ASTERISK_ARI_USER=ai_operator
|
||||
ASTERISK_ARI_PASSWORD=test-password
|
||||
ASTERISK_ARI_APP=ai-operator
|
||||
ASTERISK_MEDIA_MODE=chan_websocket
|
||||
ASTERISK_MEDIA_CODEC=slin16
|
||||
`
|
||||
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg, _, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !cfg.Dialogue.EnforceLanguageAndRegion {
|
||||
t.Fatal("dialogue enforcement should default true")
|
||||
}
|
||||
if cfg.Dialogue.DefaultLanguage != "" || cfg.Dialogue.DefaultRegionCode != "" {
|
||||
t.Fatal("dialogue defaults should be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialogueEnforcementCannotBeDisabledInProd(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "prod.env")
|
||||
content := `APP_ENV=prod
|
||||
LOG_LEVEL=info
|
||||
ASTERISK_ARI_URL=http://127.0.0.1:8088/ari
|
||||
ASTERISK_ARI_WS_URL=ws://127.0.0.1:8088/ari/events
|
||||
ASTERISK_ARI_USER=ai_operator
|
||||
ASTERISK_ARI_PASSWORD=test-password
|
||||
ASTERISK_ARI_APP=ai-operator
|
||||
ASTERISK_MEDIA_MODE=chan_websocket
|
||||
ASTERISK_MEDIA_CODEC=slin16
|
||||
DIALOGUE_ENFORCE_LANGUAGE_REGION=false
|
||||
`
|
||||
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := Load(path); err == nil {
|
||||
t.Fatal("expected prod validation error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLanguageConfigDefaults(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "language.env")
|
||||
content := `APP_ENV=dev
|
||||
LOG_LEVEL=debug
|
||||
ASTERISK_ARI_URL=http://127.0.0.1:8088/ari
|
||||
ASTERISK_ARI_WS_URL=ws://127.0.0.1:8088/ari/events
|
||||
ASTERISK_ARI_USER=ai_operator
|
||||
ASTERISK_ARI_PASSWORD=test-password
|
||||
ASTERISK_ARI_APP=ai-operator
|
||||
ASTERISK_MEDIA_MODE=chan_websocket
|
||||
ASTERISK_MEDIA_CODEC=slin16
|
||||
`
|
||||
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg, _, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !cfg.Dialogue.LanguageSelectionEnabled || cfg.Dialogue.LanguageConfidenceThreshold != 0.70 || cfg.Dialogue.LanguageChangeConfidenceThreshold != 0.90 || !cfg.Dialogue.LanguageAllowChangeAfterSelection || cfg.Dialogue.LanguageDefaultOnTimeout != "" {
|
||||
t.Fatalf("bad language defaults: %+v", cfg.Dialogue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLanguageSelectionCannotBeDisabledInProd(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "prod-language.env")
|
||||
content := `APP_ENV=prod
|
||||
LOG_LEVEL=info
|
||||
ASTERISK_ARI_URL=http://127.0.0.1:8088/ari
|
||||
ASTERISK_ARI_WS_URL=ws://127.0.0.1:8088/ari/events
|
||||
ASTERISK_ARI_USER=ai_operator
|
||||
ASTERISK_ARI_PASSWORD=test-password
|
||||
ASTERISK_ARI_APP=ai-operator
|
||||
ASTERISK_MEDIA_MODE=chan_websocket
|
||||
ASTERISK_MEDIA_CODEC=slin16
|
||||
LANGUAGE_SELECTION_ENABLED=false
|
||||
`
|
||||
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := Load(path); err == nil {
|
||||
t.Fatal("expected prod language validation error")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user