174 lines
5.7 KiB
Go
174 lines
5.7 KiB
Go
package call
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"ai-operator/internal/asterisk/ari"
|
|
)
|
|
|
|
type fakeActions struct{ answered, hungup, played []string }
|
|
|
|
func (f *fakeActions) AnswerChannel(ctx context.Context, channelID string) error {
|
|
f.answered = append(f.answered, channelID)
|
|
return nil
|
|
}
|
|
func (f *fakeActions) HangupChannel(ctx context.Context, channelID string) error {
|
|
f.hungup = append(f.hungup, channelID)
|
|
return nil
|
|
}
|
|
func (f *fakeActions) GetChannel(ctx context.Context, channelID string) (*ari.ARIChannel, error) {
|
|
return &ari.ARIChannel{ID: channelID}, nil
|
|
}
|
|
func (f *fakeActions) PlayChannel(ctx context.Context, channelID string, media string) error {
|
|
f.played = append(f.played, channelID+" "+media)
|
|
return nil
|
|
}
|
|
|
|
func startEvent(id string, args []string) ari.StasisStartEvent {
|
|
return ari.StasisStartEvent{BaseEvent: ari.BaseEvent{Type: ari.EventStasisStart}, Args: args, Channel: ari.ARIChannel{ID: id, Caller: ari.ARICallerID{Number: "+77771234567"}}}
|
|
}
|
|
|
|
func TestManagerObserveOnly(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
store := NewSessionStore()
|
|
m := NewManager(DefaultManagerConfig(ManagerModeObserveOnly, time.Millisecond), fake, store, nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"test"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(fake.answered) != 0 || len(fake.hungup) != 0 {
|
|
t.Fatal("observe-only controlled channel")
|
|
}
|
|
if store.Count() != 1 {
|
|
t.Fatalf("count=%d", store.Count())
|
|
}
|
|
}
|
|
|
|
func TestManagerCallControlTestRoute(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
m := NewManager(DefaultManagerConfig(ManagerModeCallControl, 5*time.Millisecond), fake, NewSessionStore(), nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"test"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(fake.answered) != 1 {
|
|
t.Fatalf("answered=%v", fake.answered)
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
if len(fake.hungup) != 1 {
|
|
t.Fatalf("hungup=%v", fake.hungup)
|
|
}
|
|
}
|
|
|
|
func TestManagerPlaybackDiagnostic(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
cfg := DefaultManagerConfig(ManagerModeCallControl, 5*time.Millisecond)
|
|
cfg.MediaTestMode = "playback"
|
|
m := NewManager(cfg, fake, NewSessionStore(), nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"test"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(fake.answered) != 1 {
|
|
t.Fatalf("answered=%v", fake.answered)
|
|
}
|
|
if len(fake.played) != 1 || fake.played[0] != "c1 sound:hello-world" {
|
|
t.Fatalf("played=%v", fake.played)
|
|
}
|
|
}
|
|
|
|
func TestManagerRejectsProductionAndCleans(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
store := NewSessionStore()
|
|
m := NewManager(DefaultManagerConfig(ManagerModeCallControl, time.Millisecond), fake, store, nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"production"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(fake.answered) != 0 || len(fake.hungup) != 1 {
|
|
t.Fatalf("answered=%v hungup=%v", fake.answered, fake.hungup)
|
|
}
|
|
_ = m.HandleEvent(context.Background(), ari.StasisEndEvent{BaseEvent: ari.BaseEvent{Type: ari.EventStasisEnd}, Channel: ari.ARIChannel{ID: "c1"}})
|
|
if store.Count() != 0 {
|
|
t.Fatalf("count=%d", store.Count())
|
|
}
|
|
_ = m.HandleEvent(context.Background(), startEvent("c2", []string{"test"}))
|
|
_ = m.HandleEvent(context.Background(), ari.ChannelDestroyedEvent{BaseEvent: ari.BaseEvent{Type: ari.EventChannelDestroyed}, Channel: ari.ARIChannel{ID: "c2"}})
|
|
if store.Count() != 0 {
|
|
t.Fatalf("count=%d", store.Count())
|
|
}
|
|
}
|
|
|
|
type fakeMediaStarter struct{ calls int }
|
|
|
|
func (f *fakeMediaStarter) StartCallMedia(ctx context.Context, session *CallSession) (MediaClient, error) {
|
|
f.calls++
|
|
session.MediaConnected = true
|
|
return nil, nil
|
|
}
|
|
|
|
func TestManagerMediaIntegrationAndMediaChannelIgnored(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
media := &fakeMediaStarter{}
|
|
cfg := DefaultManagerConfig(ManagerModeCallControl, time.Millisecond)
|
|
cfg.MediaEnabled = true
|
|
cfg.MediaStarter = media
|
|
m := NewManager(cfg, fake, NewSessionStore(), nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"test"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if media.calls != 1 {
|
|
t.Fatalf("media calls=%d", media.calls)
|
|
}
|
|
if err := m.HandleEvent(context.Background(), startEvent("aiop-media-c1", []string{"test"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if m.Store().Count() != 1 {
|
|
t.Fatalf("media channel treated as caller, count=%d", m.Store().Count())
|
|
}
|
|
}
|
|
|
|
func TestManagerDialogueIntegration(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
started := false
|
|
ended := false
|
|
cfg := DefaultManagerConfig(ManagerModeCallControl, time.Millisecond)
|
|
cfg.StartDialogue = func(ctx context.Context, session *CallSession) (string, error) {
|
|
started = true
|
|
if session.Route != "test" {
|
|
t.Fatalf("route=%s", session.Route)
|
|
}
|
|
return "state prompt", nil
|
|
}
|
|
cfg.EndDialogue = func(ctx context.Context, callID string, reason string) error {
|
|
ended = true
|
|
return nil
|
|
}
|
|
m := NewManager(cfg, fake, NewSessionStore(), nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"test"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !started {
|
|
t.Fatal("dialogue not started")
|
|
}
|
|
_ = m.HandleEvent(context.Background(), ari.StasisEndEvent{BaseEvent: ari.BaseEvent{Type: ari.EventStasisEnd}, Channel: ari.ARIChannel{ID: "c1"}})
|
|
if !ended {
|
|
t.Fatal("dialogue not ended")
|
|
}
|
|
}
|
|
|
|
func TestManagerDoesNotStartDialogueForProduction(t *testing.T) {
|
|
fake := &fakeActions{}
|
|
started := false
|
|
cfg := DefaultManagerConfig(ManagerModeCallControl, time.Millisecond)
|
|
cfg.StartDialogue = func(ctx context.Context, session *CallSession) (string, error) {
|
|
started = true
|
|
return "", nil
|
|
}
|
|
m := NewManager(cfg, fake, NewSessionStore(), nil)
|
|
if err := m.HandleEvent(context.Background(), startEvent("c1", []string{"production"})); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if started {
|
|
t.Fatal("dialogue started for production route")
|
|
}
|
|
}
|