85 lines
2.8 KiB
Go
85 lines
2.8 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package speech
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestContinuousSpeechWaitsForEndAndSurvivesCancellation(t *testing.T) {
|
|
for _, interrupted := range []bool{false, true} {
|
|
t.Run(fmt.Sprint(interrupted), func(t *testing.T) {
|
|
conn, server := net.Pipe()
|
|
control, controlServer := net.Pipe()
|
|
client := connectedClient(conn)
|
|
client.cancelConn, client.cancelReader, client.clientID = control, bufio.NewReader(control), 42
|
|
t.Cleanup(func() { server.Close(); controlServer.Close(); client.Close(context.Background()) })
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
began := make(chan struct{}, 1)
|
|
finished := make(chan error, 1)
|
|
go func() { finished <- client.SpeakAndWait(ctx, "First line", func() { began <- struct{}{} }) }()
|
|
server.SetDeadline(time.Now().Add(2 * time.Second))
|
|
reader := bufio.NewReader(server)
|
|
if err := exchangeSSIP(reader, server, "SET SELF NOTIFICATION ALL on\r\n", "200 OK\r\n"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, want := range []string{"SPEAK\r\n", "First line\r\n", ".\r\n"} {
|
|
got, err := reader.ReadString('\n')
|
|
if err != nil || got != want {
|
|
t.Fatalf("speech block %q, %v; want %q", got, err, want)
|
|
}
|
|
}
|
|
fmt.Fprint(server, "230 OK\r\n225-1\r\n225 QUEUED\r\n")
|
|
select {
|
|
case <-began:
|
|
t.Fatal("queue acknowledgement advanced reading position")
|
|
case <-finished:
|
|
t.Fatal("queue acknowledgement completed speech")
|
|
default:
|
|
}
|
|
fmt.Fprint(server, "701-1\r\n701-42\r\n701 BEGIN\r\n")
|
|
select {
|
|
case <-began:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("BEGIN did not update reading position")
|
|
}
|
|
if interrupted {
|
|
cancel()
|
|
controlServer.SetDeadline(time.Now().Add(time.Second))
|
|
if err := exchangeSSIP(bufio.NewReader(controlServer), controlServer, "CANCEL 42\r\n", "200 OK\r\n"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fmt.Fprint(server, "703-1\r\n703-42\r\n703 CANCELED\r\n")
|
|
} else {
|
|
fmt.Fprint(server, "702-1\r\n702-42\r\n702 END\r\n")
|
|
}
|
|
if err := exchangeSSIP(reader, server, "SET SELF NOTIFICATION ALL off\r\n", "200 OK\r\n"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := <-finished; interrupted && !errors.Is(err, context.Canceled) || !interrupted && err != nil {
|
|
t.Fatalf("completion = %v", err)
|
|
}
|
|
// The cancellation notification must not become the next SPEAK reply.
|
|
go func() { finished <- client.Speak(context.Background(), "After") }()
|
|
for range 3 {
|
|
if _, err := reader.ReadString('\n'); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
fmt.Fprint(server, "230 OK\r\n225-2\r\n225 QUEUED\r\n")
|
|
if err := <-finished; err != nil {
|
|
t.Fatalf("speech after read all: %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|