123 lines
3.2 KiB
Go
123 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
)
|
|
|
|
func TestStopClosesResponseAndRestoresMusic(t *testing.T) {
|
|
dir := t.TempDir()
|
|
helper := filepath.Join(dir, "music")
|
|
logfile := filepath.Join(dir, "calls")
|
|
script := "#!/bin/sh\ncat >> '" + logfile + "'\nprintf '{\"ok\":true}'\n"
|
|
if err := os.WriteFile(helper, []byte(script), 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Setenv("ALICE_MUSIC_HELPER", helper)
|
|
player := filepath.Join(dir, "player")
|
|
spoken := filepath.Join(dir, "spoken")
|
|
if err := os.WriteFile(player, []byte("#!/bin/sh\nexec cat > '"+spoken+"'\n"), 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Setenv("ALICE_PLAYER", player)
|
|
mutePath = filepath.Join(dir, "mute")
|
|
if err := os.WriteFile(mutePath, []byte("1"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
processing := make(chan struct{})
|
|
closed := make(chan struct{})
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ws, err := (&websocket.Upgrader{}).Upgrade(w, r, nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ws.Close()
|
|
ws.WriteJSON(message{Type: "ready"})
|
|
for {
|
|
typ, data, err := ws.ReadMessage()
|
|
if err != nil {
|
|
close(closed)
|
|
return
|
|
}
|
|
if typ == websocket.TextMessage && strings.Contains(string(data), "end") {
|
|
ws.WriteMessage(websocket.BinaryMessage, make([]byte, 4800))
|
|
close(processing)
|
|
}
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
live := &liveReader{chunks: make(chan audioFrame, 130)}
|
|
for i := 0; i < 130; i++ {
|
|
s := make([]int16, hop)
|
|
if i < 6 {
|
|
for j := range s {
|
|
s[j] = 60
|
|
}
|
|
}
|
|
live.chunks <- audioFrame{seq: uint64(i + 1), pcm: s}
|
|
}
|
|
close(live.chunks)
|
|
dialog := &conversation{commands: make(chan byte, 4)}
|
|
ctx, finish := dialog.begin()
|
|
defer finish()
|
|
result := make(chan error, 1)
|
|
go func() {
|
|
result <- exchange(ctx, "ws"+strings.TrimPrefix(srv.URL, "http"), "test", live, nil, make([]int16, 800), 12, 4*time.Second, 1200*time.Millisecond, "", 0, nil)
|
|
}()
|
|
select {
|
|
case <-processing:
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("no processing")
|
|
}
|
|
for deadline := time.Now().Add(time.Second); ; {
|
|
if info, err := os.Stat(spoken); err == nil && info.Size() > 0 {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("no audio written to player")
|
|
}
|
|
time.Sleep(5 * time.Millisecond)
|
|
}
|
|
start := time.Now()
|
|
dialog.command(1)
|
|
select {
|
|
case err := <-result:
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatal(err)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("stop did not interrupt")
|
|
}
|
|
if time.Since(start) > time.Second {
|
|
t.Fatal("slow stop")
|
|
}
|
|
select {
|
|
case <-closed:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("upstream not closed")
|
|
}
|
|
calls, _ := os.ReadFile(logfile)
|
|
if strings.Count(string(calls), "\"name\":\"duck\"") != 2 || !strings.Contains(string(calls), "\"active\":false") || strings.Contains(string(calls), "spotify_control") {
|
|
t.Fatalf("unexpected music calls %s", calls)
|
|
}
|
|
}
|
|
|
|
func TestLocalStopDoesNotPauseMusic(t *testing.T) {
|
|
dialog := &conversation{commands: make(chan byte, 4)}
|
|
dialog.command(1)
|
|
select {
|
|
case <-dialog.commands:
|
|
t.Fatal("stop queued a Spotify command")
|
|
default:
|
|
}
|
|
}
|