Files
gortsplib/internal/teste2e/server_vs_external_test.go
Alessandro Ros a5ff92f130 improve E2E tests (#822)
* add client-vs-server tests
* rewrite server-vs-external tests
2025-07-05 12:15:57 +02:00

344 lines
8.2 KiB
Go

//go:build enable_e2e_tests
package teste2e
import (
"crypto/tls"
"os"
"os/exec"
"path/filepath"
"strconv"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
)
type container struct {
name string
}
func newContainer(image string, name string, args []string) (*container, error) {
c := &container{
name: name,
}
exec.Command("docker", "kill", "gortsplib-test-"+name).Run()
exec.Command("docker", "wait", "gortsplib-test-"+name).Run()
cmd := []string{
"docker", "run",
"--network=host",
"--name=gortsplib-test-" + name,
"gortsplib-test-" + image,
}
cmd = append(cmd, args...)
ecmd := exec.Command(cmd[0], cmd[1:]...)
ecmd.Stdout = nil
ecmd.Stderr = os.Stderr
err := ecmd.Start()
if err != nil {
return nil, err
}
time.Sleep(1 * time.Second)
return c, nil
}
func (c *container) close() {
exec.Command("docker", "kill", "gortsplib-test-"+c.name).Run()
exec.Command("docker", "wait", "gortsplib-test-"+c.name).Run()
exec.Command("docker", "rm", "gortsplib-test-"+c.name).Run()
}
func (c *container) wait() int {
exec.Command("docker", "wait", "gortsplib-test-"+c.name).Run()
out, _ := exec.Command("docker", "inspect", "gortsplib-test-"+c.name,
"--format={{.State.ExitCode}}").Output()
code, _ := strconv.ParseInt(string(out[:len(out)-1]), 10, 32)
return int(code)
}
func buildImage(image string) error {
ecmd := exec.Command("docker", "build", filepath.Join("images", image),
"-t", "gortsplib-test-"+image)
ecmd.Stdout = nil
ecmd.Stderr = os.Stderr
return ecmd.Run()
}
func TestServerVsExternal(t *testing.T) {
files, err := os.ReadDir("images")
require.NoError(t, err)
var wg sync.WaitGroup
for _, file := range files {
cfile := file
wg.Add(1)
go func() {
err := buildImage(cfile.Name())
require.NoError(t, err)
wg.Done()
}()
}
wg.Wait()
for _, ca := range []struct {
publisherSoft string
publisherScheme string
publisherProto string
publisherSecure string
readerSoft string
readerScheme string
readerProto string
readerSecure string
}{
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "udp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "gstreamer",
readerScheme: "rtsp",
readerProto: "udp",
readerSecure: "unsecure",
},
{
publisherSoft: "gstreamer",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "udp",
readerSecure: "unsecure",
},
{
publisherSoft: "gstreamer",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "gstreamer",
readerScheme: "rtsp",
readerProto: "udp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "multicast",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "gstreamer",
readerScheme: "rtsp",
readerProto: "multicast",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "gstreamer",
readerScheme: "rtsp",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "gstreamer",
publisherScheme: "rtsp",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "gstreamer",
publisherScheme: "rtsp",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "gstreamer",
readerScheme: "rtsp",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "udp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsp",
publisherProto: "udp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsp",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsps",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsps",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "ffmpeg",
publisherScheme: "rtsps",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "gstreamer",
readerScheme: "rtsps",
readerProto: "tcp",
readerSecure: "unsecure",
},
{
publisherSoft: "gstreamer",
publisherScheme: "rtsps",
publisherProto: "tcp",
publisherSecure: "unsecure",
readerSoft: "ffmpeg",
readerScheme: "rtsps",
readerProto: "tcp",
readerSecure: "unsecure",
},
} {
t.Run(ca.publisherSoft+"_"+ca.publisherScheme+"_"+ca.publisherProto+"_"+ca.publisherSecure+"_"+
ca.readerSoft+"_"+ca.readerScheme+"_"+ca.readerProto+"_"+ca.readerSecure, func(t *testing.T) {
ss := &sampleServer{}
if ca.publisherScheme == "rtsps" {
cert, err := tls.X509KeyPair(serverCert, serverKey)
require.NoError(t, err)
ss.tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
}
err := ss.initialize()
require.NoError(t, err)
defer ss.close()
switch ca.publisherSoft {
case "ffmpeg":
cnt1, err := newContainer("ffmpeg", "publish", []string{
"-re",
"-stream_loop", "-1",
"-i", "emptyvideo.mkv",
"-c", "copy",
"-f", "rtsp",
"-rtsp_transport", ca.publisherProto,
ca.publisherScheme + "://localhost:8554/test/stream?key=val",
})
require.NoError(t, err)
defer cnt1.close()
case "gstreamer":
var profile string
if ca.publisherSecure == "secure" {
profile = "GST_RTSP_PROFILE_SAVP"
} else {
profile = "GST_RTSP_PROFILE_AVP"
}
cnt1, err := newContainer("gstreamer", "publish", []string{
"filesrc location=emptyvideo.mkv ! matroskademux ! video/x-h264 ! rtspclientsink " +
"location=" + ca.publisherScheme + "://127.0.0.1:8554/test/stream?key=val" +
" protocols=" + ca.publisherProto +
" profiles=" + profile +
" tls-validation-flags=0 latency=0 timeout=0 rtx-time=0",
})
require.NoError(t, err)
defer cnt1.close()
time.Sleep(1 * time.Second)
}
time.Sleep(1 * time.Second)
switch ca.readerSoft {
case "ffmpeg":
var proto string
if ca.readerProto == "multicast" {
proto = "udp_multicast"
} else {
proto = ca.readerProto
}
cnt2, err := newContainer("ffmpeg", "read", []string{
"-rtsp_transport", proto,
"-i", ca.readerScheme + "://localhost:8554/test/stream?key=val",
"-vframes", "1",
"-f", "image2",
"-y", "/dev/null",
})
require.NoError(t, err)
defer cnt2.close()
require.Equal(t, 0, cnt2.wait())
case "gstreamer":
var proto string
if ca.readerProto == "multicast" {
proto = "udp-mcast"
} else {
proto = ca.readerProto
}
cnt2, err := newContainer("gstreamer", "read", []string{
"rtspsrc location=" + ca.readerScheme + "://127.0.0.1:8554/test/stream?key=val" +
" protocols=" + proto +
" tls-validation-flags=0 latency=0 " +
"! application/x-rtp,media=video ! decodebin ! video/x-raw ! fakesink num-buffers=1",
})
require.NoError(t, err)
defer cnt2.close()
require.Equal(t, 0, cnt2.wait())
}
})
}
}