package callruntime import ( "context" "testing" "time" "git.ipao.vip/rogee/go-sip/internal/ai" ) func validConfig() Config { return Config{ARIURL: "http://127.0.0.1:1/ari", ARIWebsocketURL: "ws://127.0.0.1:1/ari/events", ARIApplication: "test", ARIUsername: "local", ARIPassword: "isolated-test-only", Endpoint: "PJSIP/local-test", MediaBind: "127.0.0.1", MediaPort: 20000, MediaFormat: "slin16", MediaSampleRate: 16000, PayloadType: 96, Pipeline: ai.MockPipeline{}} } func TestRuntimeRejectsInvalidConfigurationBeforeNetwork(t *testing.T) { for _, tc := range []struct { name string change func(*Config) }{ {"ARI URL", func(c *Config) { c.ARIURL = "" }}, {"websocket", func(c *Config) { c.ARIWebsocketURL = "" }}, {"application", func(c *Config) { c.ARIApplication = "" }}, {"username", func(c *Config) { c.ARIUsername = "" }}, {"password", func(c *Config) { c.ARIPassword = "" }}, {"endpoint", func(c *Config) { c.Endpoint = "" }}, {"media bind", func(c *Config) { c.MediaBind = "" }}, {"low media port", func(c *Config) { c.MediaPort = 1023 }}, {"high media port", func(c *Config) { c.MediaPort = 65536 }}, {"media format", func(c *Config) { c.MediaFormat = "invalid" }}, {"pipeline", func(c *Config) { c.Pipeline = nil }}, } { t.Run(tc.name, func(t *testing.T) { cfg := validConfig() tc.change(&cfg) if err := cfg.validate(); err == nil { t.Fatal("invalid configuration accepted") } if _, err := Run(context.Background(), cfg); err == nil { t.Fatal("invalid configuration reached runtime") } }) } if err := validConfig().validate(); err != nil { t.Fatal(err) } } func TestRuntimeNormalizationPreservesExplicitSettings(t *testing.T) { cfg := validConfig() cfg.AnswerTimeout = time.Second cfg.TurnWindow = 2 * time.Second cfg.FirstSpeechTimeout = 3 * time.Second cfg.MaxTurnDuration = 4 * time.Second cfg.EndSilence = 5 * time.Second cfg.MaxCallDuration = 6 * time.Second cfg.VoiceThreshold = 22 cfg.MaxTurns = 9 cfg.OpeningPrompt = "configured opening" actual := cfg.normalized() if actual.AnswerTimeout != cfg.AnswerTimeout || actual.TurnWindow != cfg.TurnWindow || actual.FirstSpeechTimeout != cfg.FirstSpeechTimeout || actual.MaxTurnDuration != cfg.MaxTurnDuration || actual.EndSilence != cfg.EndSilence || actual.MaxCallDuration != cfg.MaxCallDuration || actual.VoiceThreshold != cfg.VoiceThreshold || actual.MaxTurns != cfg.MaxTurns || actual.OpeningPrompt != cfg.OpeningPrompt { t.Fatal("explicit conversation settings were overwritten") } defaults := (Config{}).normalized() if defaults.MediaFormat != "slin16" || defaults.MediaSampleRate != 16000 || defaults.AnswerTimeout <= 0 || defaults.TurnWindow <= 0 { t.Fatal("invalid normalized transport settings") } }