mirror of
https://github.com/Quad4-Software/Reticulum-Go
synced 2026-08-29 23:48:44 -04:00
114 lines
2.2 KiB
Go
114 lines
2.2 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (c) 2024-2026 Quad4.io
|
|
|
|
package interfaces
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"os/exec"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"quad4/reticulum-go/pkg/common"
|
|
)
|
|
|
|
func TestPipeInterfaceStopDoesNotDeadlockWithReadLoop(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip()
|
|
}
|
|
if _, err := exec.LookPath("cat"); err != nil {
|
|
t.Skip("cat not available")
|
|
}
|
|
pi, err := NewPipeInterface("deadlock", "cat", true, time.Second, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
_ = pi.Stop()
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("Stop blocked >5s (possible deadlock with readLoop)")
|
|
}
|
|
}
|
|
|
|
func TestLocalClientStopDoesNotDeadlockWithReadLoop(t *testing.T) {
|
|
server, client := net.Pipe()
|
|
lc := &LocalClientInterface{
|
|
BaseInterface: NewBaseInterface("local-deadlock", common.IFTypeUnix, true),
|
|
conn: client,
|
|
done: make(chan struct{}),
|
|
}
|
|
lc.MTU = 262144
|
|
lc.Online = true
|
|
|
|
go lc.readLoop()
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
_ = lc.Stop()
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("LocalClient Stop blocked >5s")
|
|
}
|
|
_ = server.Close()
|
|
}
|
|
|
|
func TestPipeInterfaceRespawnDoesNotDeadlock(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip()
|
|
}
|
|
pr, pw := io.Pipe()
|
|
pi := &PipeInterface{
|
|
BaseInterface: NewBaseInterface("respawn-deadlock", common.IFTypePipe, true),
|
|
command: "cat",
|
|
respawnDelay: 10 * time.Millisecond,
|
|
done: make(chan struct{}),
|
|
stdout: pr,
|
|
stdin: pw,
|
|
}
|
|
pi.Online = true
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Go(func() {
|
|
pi.readLoop()
|
|
})
|
|
_ = pw.Close()
|
|
|
|
waitDone := make(chan struct{})
|
|
go func() {
|
|
wg.Wait()
|
|
close(waitDone)
|
|
}()
|
|
|
|
select {
|
|
case <-waitDone:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("readLoop blocked >5s after pipe close")
|
|
}
|
|
pi.Mutex.Lock()
|
|
pi.Enabled = false
|
|
pi.Mutex.Unlock()
|
|
_ = pi.Stop()
|
|
}
|
|
|
|
func TestLocalServerSpawnHookDoesNotDeadlock(t *testing.T) {
|
|
ln, err := NewLocalServerInterface(0, "", false, func(*LocalClientInterface) {}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ln.spawnHook == nil {
|
|
t.Fatal("expected spawn hook")
|
|
}
|
|
}
|