mirror of
https://github.com/bluenviron/mediamtx
synced 2025-01-18 21:10:54 +00:00
api: add tests
This commit is contained in:
parent
5943660ab3
commit
0535ab8e9c
@ -137,7 +137,6 @@ func loadConfPathData(ctx *gin.Context) (interface{}, error) {
|
||||
}
|
||||
|
||||
type apiPathsItem struct {
|
||||
Name string `json:"name"`
|
||||
ConfName string `json:"confName"`
|
||||
Conf *conf.PathConf `json:"conf"`
|
||||
Source interface{} `json:"source"`
|
||||
@ -146,7 +145,7 @@ type apiPathsItem struct {
|
||||
}
|
||||
|
||||
type apiPathsListData struct {
|
||||
Items []apiPathsItem `json:"items"`
|
||||
Items map[string]apiPathsItem `json:"items"`
|
||||
}
|
||||
|
||||
type apiPathsListRes1 struct {
|
||||
@ -167,13 +166,12 @@ type apiPathsListReq2 struct {
|
||||
Res chan apiPathsListRes2
|
||||
}
|
||||
|
||||
type apiRTSPSessionsItem struct {
|
||||
ID string `json:"id"`
|
||||
type apiRTSPSessionsListItem struct {
|
||||
RemoteAddr string `json:"remoteAddr"`
|
||||
}
|
||||
|
||||
type apiRTSPSessionsListData struct {
|
||||
Items []apiRTSPSessionsItem `json:"items"`
|
||||
Items map[string]apiRTSPSessionsListItem `json:"items"`
|
||||
}
|
||||
|
||||
type apiRTSPSessionsListRes struct {
|
||||
@ -193,12 +191,11 @@ type apiRTSPSessionsKickReq struct {
|
||||
}
|
||||
|
||||
type apiRTMPConnsListItem struct {
|
||||
ID string `json:"id"`
|
||||
RemoteAddr string `json:"remoteAddr"`
|
||||
}
|
||||
|
||||
type apiRTMPConnsListData struct {
|
||||
Items []apiRTMPConnsListItem `json:"items"`
|
||||
Items map[string]apiRTMPConnsListItem `json:"items"`
|
||||
}
|
||||
|
||||
type apiRTMPConnsListRes struct {
|
||||
@ -357,6 +354,10 @@ func (a *api) onConfigSet(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
go a.parent.OnAPIConfigSet(&newConf)
|
||||
@ -393,6 +394,10 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
go a.parent.OnAPIConfigSet(&newConf)
|
||||
@ -428,6 +433,10 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
go a.parent.OnAPIConfigSet(&newConf)
|
||||
@ -456,6 +465,10 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
go a.parent.OnAPIConfigSet(&newConf)
|
||||
@ -465,7 +478,7 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
|
||||
|
||||
func (a *api) onPathsList(ctx *gin.Context) {
|
||||
data := apiPathsListData{
|
||||
Items: []apiPathsItem{},
|
||||
Items: make(map[string]apiPathsItem),
|
||||
}
|
||||
|
||||
res := a.pathManager.OnAPIPathsList(apiPathsListReq1{})
|
||||
@ -488,7 +501,7 @@ func (a *api) onRTSPSessionsList(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
data := apiRTSPSessionsListData{
|
||||
Items: []apiRTSPSessionsItem{},
|
||||
Items: make(map[string]apiRTSPSessionsListItem),
|
||||
}
|
||||
|
||||
if a.rtspServer != nil {
|
||||
@ -544,7 +557,7 @@ func (a *api) onRTMPConnsList(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
data := apiRTMPConnsListData{
|
||||
Items: []apiRTMPConnsListItem{},
|
||||
Items: make(map[string]apiRTMPConnsListItem),
|
||||
}
|
||||
|
||||
res := a.rtmpServer.OnAPIRTMPConnsList(apiRTMPConnsListReq{Data: &data})
|
||||
|
283
internal/core/api_test.go
Normal file
283
internal/core/api_test.go
Normal file
@ -0,0 +1,283 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aler9/gortsplib"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func httpRequest(method string, ur string, in interface{}, out interface{}) error {
|
||||
buf, err := func() (io.Reader, error) {
|
||||
if in == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
byts, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bytes.NewBuffer(byts), nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, ur, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("bad status code: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
if out == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return json.NewDecoder(res.Body).Decode(out)
|
||||
}
|
||||
|
||||
func TestAPIConfigGet(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
var out map[string]interface{}
|
||||
err := httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, out["api"])
|
||||
}
|
||||
|
||||
func TestAPIConfigSet(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
err := httpRequest(http.MethodPost, "http://localhost:9997/config/set", map[string]interface{}{
|
||||
"rtmpDisable": true,
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
var out map[string]interface{}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, out["rtmpDisable"])
|
||||
}
|
||||
|
||||
func TestAPIConfigPathsAdd(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
err := httpRequest(http.MethodPost, "http://localhost:9997/config/paths/add/mypath", map[string]interface{}{
|
||||
"source": "rtsp://127.0.0.1:9999/mypath",
|
||||
"sourceOnDemand": true,
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out map[string]interface{}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rtsp://127.0.0.1:9999/mypath", out["paths"].(map[string]interface{})["mypath"].(map[string]interface{})["source"])
|
||||
}
|
||||
|
||||
func TestAPIConfigPathsEdit(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
err := httpRequest(http.MethodPost, "http://localhost:9997/config/paths/add/mypath", map[string]interface{}{
|
||||
"source": "rtsp://127.0.0.1:9999/mypath",
|
||||
"sourceOnDemand": true,
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = httpRequest(http.MethodPost, "http://localhost:9997/config/paths/edit/mypath", map[string]interface{}{
|
||||
"source": "rtsp://127.0.0.1:9998/mypath",
|
||||
"sourceOnDemand": true,
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out struct {
|
||||
Paths map[string]struct {
|
||||
Source string `json:"source"`
|
||||
} `json:"paths"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rtsp://127.0.0.1:9998/mypath", out.Paths["mypath"].Source)
|
||||
}
|
||||
|
||||
func TestAPIConfigPathsDelete(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
err := httpRequest(http.MethodPost, "http://localhost:9997/config/paths/add/mypath", map[string]interface{}{
|
||||
"source": "rtsp://127.0.0.1:9999/mypath",
|
||||
"sourceOnDemand": true,
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = httpRequest(http.MethodPost, "http://localhost:9997/config/paths/delete/mypath", nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out struct {
|
||||
Paths map[string]interface{} `json:"paths"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
|
||||
require.NoError(t, err)
|
||||
_, ok = out.Paths["mypath"]
|
||||
require.Equal(t, false, ok)
|
||||
}
|
||||
|
||||
func TestAPIPathsList(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n" +
|
||||
"paths:\n" +
|
||||
" mypath:\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
var out struct {
|
||||
Items map[string]interface{} `json:"items"`
|
||||
}
|
||||
err := httpRequest(http.MethodGet, "http://localhost:9997/paths/list", nil, &out)
|
||||
require.NoError(t, err)
|
||||
_, ok = out.Items["mypath"]
|
||||
require.Equal(t, true, ok)
|
||||
}
|
||||
|
||||
func TestAPIRTSPSessionsList(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
track, err := gortsplib.NewTrackH264(96, []byte("123456"), []byte("123456"))
|
||||
require.NoError(t, err)
|
||||
|
||||
source, err := gortsplib.DialPublish("rtsp://localhost:8554/mypath",
|
||||
gortsplib.Tracks{track})
|
||||
require.NoError(t, err)
|
||||
defer source.Close()
|
||||
|
||||
var out struct {
|
||||
Items map[string]struct{} `json:"items"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/rtspsessions/list", nil, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(out.Items))
|
||||
}
|
||||
|
||||
func TestAPIRTSPSessionsKick(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
track, err := gortsplib.NewTrackH264(96, []byte("123456"), []byte("123456"))
|
||||
require.NoError(t, err)
|
||||
|
||||
source, err := gortsplib.DialPublish("rtsp://localhost:8554/mypath",
|
||||
gortsplib.Tracks{track})
|
||||
require.NoError(t, err)
|
||||
defer source.Close()
|
||||
|
||||
var out1 struct {
|
||||
Items map[string]struct{} `json:"items"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/rtspsessions/list", nil, &out1)
|
||||
require.NoError(t, err)
|
||||
|
||||
var firstID string
|
||||
for k := range out1.Items {
|
||||
firstID = k
|
||||
}
|
||||
|
||||
err = httpRequest(http.MethodPost, "http://localhost:9997/rtspsessions/kick/"+firstID, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out2 struct {
|
||||
Items map[string]struct{} `json:"items"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/rtspsessions/list", nil, &out2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(out2.Items))
|
||||
}
|
||||
|
||||
func TestAPIRTMPConnsList(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
cnt1, err := newContainer("ffmpeg", "source", []string{
|
||||
"-re",
|
||||
"-stream_loop", "-1",
|
||||
"-i", "emptyvideo.mkv",
|
||||
"-c", "copy",
|
||||
"-f", "flv",
|
||||
"rtmp://localhost:1935/test1/test2",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer cnt1.close()
|
||||
|
||||
var out struct {
|
||||
Items map[string]struct{} `json:"items"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/rtmpconns/list", nil, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(out.Items))
|
||||
}
|
||||
|
||||
func TestAPIRTSPConnsKick(t *testing.T) {
|
||||
p, ok := newInstance("api: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
cnt1, err := newContainer("ffmpeg", "source", []string{
|
||||
"-re",
|
||||
"-stream_loop", "-1",
|
||||
"-i", "emptyvideo.mkv",
|
||||
"-c", "copy",
|
||||
"-f", "flv",
|
||||
"rtmp://localhost:1935/test1/test2",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer cnt1.close()
|
||||
|
||||
var out1 struct {
|
||||
Items map[string]struct{} `json:"items"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/rtmpconns/list", nil, &out1)
|
||||
require.NoError(t, err)
|
||||
|
||||
var firstID string
|
||||
for k := range out1.Items {
|
||||
firstID = k
|
||||
}
|
||||
|
||||
err = httpRequest(http.MethodPost, "http://localhost:9997/rtmpconns/kick/"+firstID, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var out2 struct {
|
||||
Items map[string]struct{} `json:"items"`
|
||||
}
|
||||
err = httpRequest(http.MethodGet, "http://localhost:9997/rtmpconns/list", nil, &out2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(out2.Items))
|
||||
}
|
@ -426,8 +426,7 @@ outer:
|
||||
pa.onReaderPause(req)
|
||||
|
||||
case req := <-pa.apiPathsList:
|
||||
req.Data.Items = append(req.Data.Items, apiPathsItem{
|
||||
Name: pa.name,
|
||||
req.Data.Items[pa.name] = apiPathsItem{
|
||||
ConfName: pa.confName,
|
||||
Conf: pa.conf,
|
||||
Source: func() interface{} {
|
||||
@ -444,7 +443,7 @@ outer:
|
||||
}
|
||||
return ret
|
||||
}(),
|
||||
})
|
||||
}
|
||||
req.Res <- apiPathsListRes2{}
|
||||
|
||||
case <-pa.ctx.Done():
|
||||
|
@ -159,10 +159,9 @@ outer:
|
||||
|
||||
case req := <-s.apiRTMPConnsList:
|
||||
for c := range s.conns {
|
||||
req.Data.Items = append(req.Data.Items, apiRTMPConnsListItem{
|
||||
ID: c.ID(),
|
||||
req.Data.Items[c.ID()] = apiRTMPConnsListItem{
|
||||
RemoteAddr: c.RemoteAddr().String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
req.Res <- apiRTMPConnsListRes{}
|
||||
|
||||
|
@ -352,10 +352,9 @@ func (s *rtspServer) OnAPIRTSPSessionsList(req apiRTSPSessionsListReq) apiRTSPSe
|
||||
|
||||
s.mutex.RLock()
|
||||
for _, s := range s.sessions {
|
||||
req.Data.Items = append(req.Data.Items, apiRTSPSessionsItem{
|
||||
ID: s.ID(),
|
||||
req.Data.Items[s.ID()] = apiRTSPSessionsListItem{
|
||||
RemoteAddr: s.RemoteAddr().String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
s.mutex.RUnlock()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user