78 lines
3.1 KiB
Go
78 lines
3.1 KiB
Go
package asterisk
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/CyCoreSystems/ari/v5"
|
|
)
|
|
|
|
type answerEvents struct {
|
|
ari.Subscription
|
|
events chan ari.Event
|
|
}
|
|
|
|
func (f answerEvents) Events() <-chan ari.Event { return f.events }
|
|
func (f answerEvents) Cancel() {}
|
|
|
|
func TestAwaitNativeAnswerRequiresMatchingStasisStart(t *testing.T) {
|
|
sub := answerEvents{events: make(chan ari.Event, 3)}
|
|
sub.events <- &ari.StasisStart{EventData: ari.EventData{Type: "StasisStart"}, Channel: ari.ChannelData{ID: "someone-else"}}
|
|
sub.events <- &ari.ChannelStateChange{EventData: ari.EventData{Type: "ChannelStateChange"}, Channel: ari.ChannelData{ID: "exec-1", State: "Up"}}
|
|
sub.events <- &ari.StasisStart{EventData: ari.EventData{Type: "StasisStart"}, Channel: ari.ChannelData{ID: "exec-1"}}
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
if err := awaitStasisStart(ctx, sub, "exec-1"); err != nil {
|
|
t.Fatalf("actual answered channel must enter the approved Stasis application: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAwaitNativeAnswerFailsClosedOnHangupOrEventLoss(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
event ari.Event
|
|
}{
|
|
{"hangup", &ari.ChannelHangupRequest{EventData: ari.EventData{Type: "ChannelHangupRequest"}, Channel: ari.ChannelData{ID: "exec-1"}, Cause: 17}},
|
|
{"destroyed", &ari.ChannelDestroyed{EventData: ari.EventData{Type: "ChannelDestroyed"}, Channel: ari.ChannelData{ID: "exec-1"}, Cause: 17}},
|
|
{"stasis-ended", &ari.StasisEnd{EventData: ari.EventData{Type: "StasisEnd"}, Channel: ari.ChannelData{ID: "exec-1"}}},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
sub := answerEvents{events: make(chan ari.Event, 1)}
|
|
sub.events <- tc.event
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
if err := awaitStasisStart(ctx, sub, "exec-1"); err == nil || !strings.Contains(err.Error(), "before StasisStart") {
|
|
t.Fatalf("failed origination must not count as answered: %v", err)
|
|
}
|
|
})
|
|
}
|
|
t.Run("empty-event", func(t *testing.T) {
|
|
sub := answerEvents{events: make(chan ari.Event, 1)}
|
|
sub.events <- nil
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
if err := awaitStasisStart(ctx, sub, "exec-1"); err == nil || !strings.Contains(err.Error(), "empty event") {
|
|
t.Fatalf("empty ARI event cannot be ignored as if the stream was healthy: %v", err)
|
|
}
|
|
})
|
|
t.Run("subscription-lost", func(t *testing.T) {
|
|
sub := answerEvents{events: make(chan ari.Event)}
|
|
close(sub.events)
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
if err := awaitStasisStart(ctx, sub, "exec-1"); err == nil || !strings.Contains(err.Error(), "subscription closed") {
|
|
t.Fatalf("event loss cannot be interpreted as answer: %v", err)
|
|
}
|
|
})
|
|
t.Run("deadline", func(t *testing.T) {
|
|
sub := answerEvents{events: make(chan ari.Event)}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
if err := awaitStasisStart(ctx, sub, "exec-1"); err == nil || !strings.Contains(err.Error(), "deadline or cancellation") {
|
|
t.Fatalf("expired answer window cannot be interpreted as answer: %v", err)
|
|
}
|
|
})
|
|
}
|